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__(impl, expl, default, optional, _decoded)
2756 self._bound_min, self._bound_max = getattr(
2760 ) if bounds is None else bounds
2761 if value is not None:
2762 self._value = self._value_sanitize(value)
2763 if default is not None:
2764 default = self._value_sanitize(default)
2765 self.default = self.__class__(
2770 if self._value is None:
2771 self._value = default
2773 tag_klass, _, tag_num = tag_decode(self.tag)
2774 self.tag_constructed = tag_encode(
2776 form=TagFormConstructed,
2780 def _value_sanitize(self, value):
2781 if isinstance(value, binary_type):
2783 elif issubclass(value.__class__, OctetString):
2784 value = value._value
2786 raise InvalidValueType((self.__class__, bytes))
2787 if not self._bound_min <= len(value) <= self._bound_max:
2788 raise BoundsError(self._bound_min, len(value), self._bound_max)
2793 return self._value is not None
2796 obj = self.__class__()
2797 obj._value = self._value
2798 obj._bound_min = self._bound_min
2799 obj._bound_max = self._bound_max
2801 obj._expl = self._expl
2802 obj.default = self.default
2803 obj.optional = self.optional
2804 obj.offset = self.offset
2805 obj.llen = self.llen
2806 obj.vlen = self.vlen
2807 obj.expl_lenindef = self.expl_lenindef
2808 obj.lenindef = self.lenindef
2809 obj.ber_encoded = self.ber_encoded
2812 def __bytes__(self):
2813 self._assert_ready()
2816 def __eq__(self, their):
2817 if isinstance(their, binary_type):
2818 return self._value == their
2819 if not issubclass(their.__class__, OctetString):
2822 self._value == their._value and
2823 self.tag == their.tag and
2824 self._expl == their._expl
2827 def __lt__(self, their):
2828 return self._value < their._value
2839 return self.__class__(
2842 (self._bound_min, self._bound_max)
2843 if bounds is None else bounds
2845 impl=self.tag if impl is None else impl,
2846 expl=self._expl if expl is None else expl,
2847 default=self.default if default is None else default,
2848 optional=self.optional if optional is None else optional,
2852 self._assert_ready()
2855 len_encode(len(self._value)),
2859 def _decode_chunk(self, lv, offset, decode_path):
2861 l, llen, v = len_decode(lv)
2862 except DecodeError as err:
2863 raise err.__class__(
2865 klass=self.__class__,
2866 decode_path=decode_path,
2870 raise NotEnoughData(
2871 "encoded length is longer than data",
2872 klass=self.__class__,
2873 decode_path=decode_path,
2876 v, tail = v[:l], v[l:]
2878 obj = self.__class__(
2880 bounds=(self._bound_min, self._bound_max),
2883 default=self.default,
2884 optional=self.optional,
2885 _decoded=(offset, llen, l),
2887 except DecodeError as err:
2890 klass=self.__class__,
2891 decode_path=decode_path,
2894 except BoundsError as err:
2897 klass=self.__class__,
2898 decode_path=decode_path,
2903 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2905 t, tlen, lv = tag_strip(tlv)
2906 except DecodeError as err:
2907 raise err.__class__(
2909 klass=self.__class__,
2910 decode_path=decode_path,
2916 return self._decode_chunk(lv, offset, decode_path)
2917 if t == self.tag_constructed:
2918 if not ctx.get("bered", False):
2920 "unallowed BER constructed encoding",
2921 klass=self.__class__,
2922 decode_path=decode_path,
2929 l, llen, v = len_decode(lv)
2930 except LenIndefForm:
2931 llen, l, v = 1, 0, lv[1:]
2933 except DecodeError as err:
2934 raise err.__class__(
2936 klass=self.__class__,
2937 decode_path=decode_path,
2941 raise NotEnoughData(
2942 "encoded length is longer than data",
2943 klass=self.__class__,
2944 decode_path=decode_path,
2948 sub_offset = offset + tlen + llen
2952 if v[:EOC_LEN].tobytes() == EOC:
2959 "chunk out of bounds",
2960 klass=self.__class__,
2961 decode_path=decode_path + (str(len(chunks) - 1),),
2962 offset=chunks[-1].offset,
2964 sub_decode_path = decode_path + (str(len(chunks)),)
2966 chunk, v_tail = OctetString().decode(
2969 decode_path=sub_decode_path,
2972 _ctx_immutable=False,
2976 "expected OctetString encoded chunk",
2977 klass=self.__class__,
2978 decode_path=sub_decode_path,
2981 chunks.append(chunk)
2982 sub_offset += chunk.tlvlen
2983 vlen += chunk.tlvlen
2986 obj = self.__class__(
2987 value=b"".join(bytes(chunk) for chunk in chunks),
2988 bounds=(self._bound_min, self._bound_max),
2991 default=self.default,
2992 optional=self.optional,
2993 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2995 except DecodeError as err:
2998 klass=self.__class__,
2999 decode_path=decode_path,
3002 except BoundsError as err:
3005 klass=self.__class__,
3006 decode_path=decode_path,
3009 obj.lenindef = lenindef
3010 obj.ber_encoded = True
3011 return obj, (v[EOC_LEN:] if lenindef else v)
3013 klass=self.__class__,
3014 decode_path=decode_path,
3019 return pp_console_row(next(self.pps()))
3021 def pps(self, decode_path=()):
3024 asn1_type_name=self.asn1_type_name,
3025 obj_name=self.__class__.__name__,
3026 decode_path=decode_path,
3027 value=("%d bytes" % len(self._value)) if self.ready else None,
3028 blob=self._value if self.ready else None,
3029 optional=self.optional,
3030 default=self == self.default,
3031 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3032 expl=None if self._expl is None else tag_decode(self._expl),
3037 expl_offset=self.expl_offset if self.expled else None,
3038 expl_tlen=self.expl_tlen if self.expled else None,
3039 expl_llen=self.expl_llen if self.expled else None,
3040 expl_vlen=self.expl_vlen if self.expled else None,
3041 expl_lenindef=self.expl_lenindef,
3042 lenindef=self.lenindef,
3043 ber_encoded=self.ber_encoded,
3046 defined_by, defined = self.defined or (None, None)
3047 if defined_by is not None:
3049 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3051 for pp in self.pps_lenindef(decode_path):
3056 """``NULL`` null object
3064 tag_default = tag_encode(5)
3065 asn1_type_name = "NULL"
3069 value=None, # unused, but Sequence passes it
3076 :param bytes impl: override default tag with ``IMPLICIT`` one
3077 :param bytes expl: override default tag with ``EXPLICIT`` one
3078 :param bool optional: is object ``OPTIONAL`` in sequence
3080 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3088 obj = self.__class__()
3090 obj._expl = self._expl
3091 obj.default = self.default
3092 obj.optional = self.optional
3093 obj.offset = self.offset
3094 obj.llen = self.llen
3095 obj.vlen = self.vlen
3096 obj.expl_lenindef = self.expl_lenindef
3097 obj.lenindef = self.lenindef
3098 obj.ber_encoded = self.ber_encoded
3101 def __eq__(self, their):
3102 if not issubclass(their.__class__, Null):
3105 self.tag == their.tag and
3106 self._expl == their._expl
3116 return self.__class__(
3117 impl=self.tag if impl is None else impl,
3118 expl=self._expl if expl is None else expl,
3119 optional=self.optional if optional is None else optional,
3123 return self.tag + len_encode(0)
3125 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3127 t, _, lv = tag_strip(tlv)
3128 except DecodeError as err:
3129 raise err.__class__(
3131 klass=self.__class__,
3132 decode_path=decode_path,
3137 klass=self.__class__,
3138 decode_path=decode_path,
3141 if tag_only: # pragma: no cover
3144 l, _, v = len_decode(lv)
3145 except DecodeError as err:
3146 raise err.__class__(
3148 klass=self.__class__,
3149 decode_path=decode_path,
3153 raise InvalidLength(
3154 "Null must have zero length",
3155 klass=self.__class__,
3156 decode_path=decode_path,
3159 obj = self.__class__(
3162 optional=self.optional,
3163 _decoded=(offset, 1, 0),
3168 return pp_console_row(next(self.pps()))
3170 def pps(self, decode_path=()):
3173 asn1_type_name=self.asn1_type_name,
3174 obj_name=self.__class__.__name__,
3175 decode_path=decode_path,
3176 optional=self.optional,
3177 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3178 expl=None if self._expl is None else tag_decode(self._expl),
3183 expl_offset=self.expl_offset if self.expled else None,
3184 expl_tlen=self.expl_tlen if self.expled else None,
3185 expl_llen=self.expl_llen if self.expled else None,
3186 expl_vlen=self.expl_vlen if self.expled else None,
3187 expl_lenindef=self.expl_lenindef,
3190 for pp in self.pps_lenindef(decode_path):
3194 class ObjectIdentifier(Obj):
3195 """``OBJECT IDENTIFIER`` OID type
3197 >>> oid = ObjectIdentifier((1, 2, 3))
3198 OBJECT IDENTIFIER 1.2.3
3199 >>> oid == ObjectIdentifier("1.2.3")
3205 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3206 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3208 >>> str(ObjectIdentifier((3, 1)))
3209 Traceback (most recent call last):
3210 pyderasn.InvalidOID: unacceptable first arc value
3212 __slots__ = ("defines",)
3213 tag_default = tag_encode(6)
3214 asn1_type_name = "OBJECT IDENTIFIER"
3227 :param value: set the value. Either tuples of integers,
3228 string of "."-concatenated integers, or
3229 :py:class:`pyderasn.ObjectIdentifier` object
3230 :param defines: sequence of tuples. Each tuple has two elements.
3231 First one is relative to current one decode
3232 path, aiming to the field defined by that OID.
3233 Read about relative path in
3234 :py:func:`pyderasn.abs_decode_path`. Second
3235 tuple element is ``{OID: pyderasn.Obj()}``
3236 dictionary, mapping between current OID value
3237 and structure applied to defined field.
3238 :ref:`Read about DEFINED BY <definedby>`
3239 :param bytes impl: override default tag with ``IMPLICIT`` one
3240 :param bytes expl: override default tag with ``EXPLICIT`` one
3241 :param default: set default value. Type same as in ``value``
3242 :param bool optional: is object ``OPTIONAL`` in sequence
3244 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3246 if value is not None:
3247 self._value = self._value_sanitize(value)
3248 if default is not None:
3249 default = self._value_sanitize(default)
3250 self.default = self.__class__(
3255 if self._value is None:
3256 self._value = default
3257 self.defines = defines
3259 def __add__(self, their):
3260 if isinstance(their, self.__class__):
3261 return self.__class__(self._value + their._value)
3262 if isinstance(their, tuple):
3263 return self.__class__(self._value + their)
3264 raise InvalidValueType((self.__class__, tuple))
3266 def _value_sanitize(self, value):
3267 if issubclass(value.__class__, ObjectIdentifier):
3269 if isinstance(value, string_types):
3271 value = tuple(int(arc) for arc in value.split("."))
3273 raise InvalidOID("unacceptable arcs values")
3274 if isinstance(value, tuple):
3276 raise InvalidOID("less than 2 arcs")
3277 first_arc = value[0]
3278 if first_arc in (0, 1):
3279 if not (0 <= value[1] <= 39):
3280 raise InvalidOID("second arc is too wide")
3281 elif first_arc == 2:
3284 raise InvalidOID("unacceptable first arc value")
3286 raise InvalidValueType((self.__class__, str, tuple))
3290 return self._value is not None
3293 obj = self.__class__()
3294 obj._value = self._value
3295 obj.defines = self.defines
3297 obj._expl = self._expl
3298 obj.default = self.default
3299 obj.optional = self.optional
3300 obj.offset = self.offset
3301 obj.llen = self.llen
3302 obj.vlen = self.vlen
3303 obj.expl_lenindef = self.expl_lenindef
3304 obj.lenindef = self.lenindef
3305 obj.ber_encoded = self.ber_encoded
3309 self._assert_ready()
3310 return iter(self._value)
3313 return ".".join(str(arc) for arc in self._value or ())
3316 self._assert_ready()
3319 bytes(self._expl or b"") +
3320 str(self._value).encode("ascii"),
3323 def __eq__(self, their):
3324 if isinstance(their, tuple):
3325 return self._value == their
3326 if not issubclass(their.__class__, ObjectIdentifier):
3329 self.tag == their.tag and
3330 self._expl == their._expl and
3331 self._value == their._value
3334 def __lt__(self, their):
3335 return self._value < their._value
3346 return self.__class__(
3348 defines=self.defines if defines is None else defines,
3349 impl=self.tag if impl is None else impl,
3350 expl=self._expl if expl is None else expl,
3351 default=self.default if default is None else default,
3352 optional=self.optional if optional is None else optional,
3356 self._assert_ready()
3358 first_value = value[1]
3359 first_arc = value[0]
3362 elif first_arc == 1:
3364 elif first_arc == 2:
3366 else: # pragma: no cover
3367 raise RuntimeError("invalid arc is stored")
3368 octets = [zero_ended_encode(first_value)]
3369 for arc in value[2:]:
3370 octets.append(zero_ended_encode(arc))
3371 v = b"".join(octets)
3372 return b"".join((self.tag, len_encode(len(v)), v))
3374 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3376 t, _, lv = tag_strip(tlv)
3377 except DecodeError as err:
3378 raise err.__class__(
3380 klass=self.__class__,
3381 decode_path=decode_path,
3386 klass=self.__class__,
3387 decode_path=decode_path,
3390 if tag_only: # pragma: no cover
3393 l, llen, v = len_decode(lv)
3394 except DecodeError as err:
3395 raise err.__class__(
3397 klass=self.__class__,
3398 decode_path=decode_path,
3402 raise NotEnoughData(
3403 "encoded length is longer than data",
3404 klass=self.__class__,
3405 decode_path=decode_path,
3409 raise NotEnoughData(
3411 klass=self.__class__,
3412 decode_path=decode_path,
3415 v, tail = v[:l], v[l:]
3422 octet = indexbytes(v, i)
3423 if i == 0 and octet == 0x80:
3424 if ctx.get("bered", False):
3427 raise DecodeError("non normalized arc encoding")
3428 arc = (arc << 7) | (octet & 0x7F)
3429 if octet & 0x80 == 0:
3437 klass=self.__class__,
3438 decode_path=decode_path,
3442 second_arc = arcs[0]
3443 if 0 <= second_arc <= 39:
3445 elif 40 <= second_arc <= 79:
3451 obj = self.__class__(
3452 value=tuple([first_arc, second_arc] + arcs[1:]),
3455 default=self.default,
3456 optional=self.optional,
3457 _decoded=(offset, llen, l),
3460 obj.ber_encoded = True
3464 return pp_console_row(next(self.pps()))
3466 def pps(self, decode_path=()):
3469 asn1_type_name=self.asn1_type_name,
3470 obj_name=self.__class__.__name__,
3471 decode_path=decode_path,
3472 value=str(self) if self.ready else None,
3473 optional=self.optional,
3474 default=self == self.default,
3475 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3476 expl=None if self._expl is None else tag_decode(self._expl),
3481 expl_offset=self.expl_offset if self.expled else None,
3482 expl_tlen=self.expl_tlen if self.expled else None,
3483 expl_llen=self.expl_llen if self.expled else None,
3484 expl_vlen=self.expl_vlen if self.expled else None,
3485 expl_lenindef=self.expl_lenindef,
3486 ber_encoded=self.ber_encoded,
3489 for pp in self.pps_lenindef(decode_path):
3493 class Enumerated(Integer):
3494 """``ENUMERATED`` integer type
3496 This type is identical to :py:class:`pyderasn.Integer`, but requires
3497 schema to be specified and does not accept values missing from it.
3500 tag_default = tag_encode(10)
3501 asn1_type_name = "ENUMERATED"
3512 bounds=None, # dummy argument, workability for Integer.decode
3514 super(Enumerated, self).__init__(
3515 value, bounds, impl, expl,default, optional, _specs, _decoded,
3517 if len(self.specs) == 0:
3518 raise ValueError("schema must be specified")
3520 def _value_sanitize(self, value):
3521 if isinstance(value, self.__class__):
3522 value = value._value
3523 elif isinstance(value, integer_types):
3524 for _value in itervalues(self.specs):
3529 "unknown integer value: %s" % value,
3530 klass=self.__class__,
3532 elif isinstance(value, string_types):
3533 value = self.specs.get(value)
3535 raise ObjUnknown("integer value: %s" % value)
3537 raise InvalidValueType((self.__class__, int, str))
3541 obj = self.__class__(_specs=self.specs)
3542 obj._value = self._value
3543 obj._bound_min = self._bound_min
3544 obj._bound_max = self._bound_max
3546 obj._expl = self._expl
3547 obj.default = self.default
3548 obj.optional = self.optional
3549 obj.offset = self.offset
3550 obj.llen = self.llen
3551 obj.vlen = self.vlen
3552 obj.expl_lenindef = self.expl_lenindef
3553 obj.lenindef = self.lenindef
3554 obj.ber_encoded = self.ber_encoded
3566 return self.__class__(
3568 impl=self.tag if impl is None else impl,
3569 expl=self._expl if expl is None else expl,
3570 default=self.default if default is None else default,
3571 optional=self.optional if optional is None else optional,
3576 def escape_control_unicode(c):
3577 if unicat(c).startswith("C"):
3578 c = repr(c).lstrip("u").strip("'")
3582 class CommonString(OctetString):
3583 """Common class for all strings
3585 Everything resembles :py:class:`pyderasn.OctetString`, except
3586 ability to deal with unicode text strings.
3588 >>> hexenc("привет мир".encode("utf-8"))
3589 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3590 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3592 >>> s = UTF8String("привет мир")
3593 UTF8String UTF8String привет мир
3595 'привет мир'
3596 >>> hexenc(bytes(s))
3597 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3599 >>> PrintableString("привет мир")
3600 Traceback (most recent call last):
3601 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3603 >>> BMPString("ада", bounds=(2, 2))
3604 Traceback (most recent call last):
3605 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3606 >>> s = BMPString("ад", bounds=(2, 2))
3609 >>> hexenc(bytes(s))
3617 * - :py:class:`pyderasn.UTF8String`
3619 * - :py:class:`pyderasn.NumericString`
3621 * - :py:class:`pyderasn.PrintableString`
3623 * - :py:class:`pyderasn.TeletexString`
3625 * - :py:class:`pyderasn.T61String`
3627 * - :py:class:`pyderasn.VideotexString`
3629 * - :py:class:`pyderasn.IA5String`
3631 * - :py:class:`pyderasn.GraphicString`
3633 * - :py:class:`pyderasn.VisibleString`
3635 * - :py:class:`pyderasn.ISO646String`
3637 * - :py:class:`pyderasn.GeneralString`
3639 * - :py:class:`pyderasn.UniversalString`
3641 * - :py:class:`pyderasn.BMPString`
3644 __slots__ = ("encoding",)
3646 def _value_sanitize(self, value):
3648 value_decoded = None
3649 if isinstance(value, self.__class__):
3650 value_raw = value._value
3651 elif isinstance(value, text_type):
3652 value_decoded = value
3653 elif isinstance(value, binary_type):
3656 raise InvalidValueType((self.__class__, text_type, binary_type))
3659 value_decoded.encode(self.encoding)
3660 if value_raw is None else value_raw
3663 value_raw.decode(self.encoding)
3664 if value_decoded is None else value_decoded
3666 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3667 raise DecodeError(str(err))
3668 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3676 def __eq__(self, their):
3677 if isinstance(their, binary_type):
3678 return self._value == their
3679 if isinstance(their, text_type):
3680 return self._value == their.encode(self.encoding)
3681 if not isinstance(their, self.__class__):
3684 self._value == their._value and
3685 self.tag == their.tag and
3686 self._expl == their._expl
3689 def __unicode__(self):
3691 return self._value.decode(self.encoding)
3692 return text_type(self._value)
3695 return pp_console_row(next(self.pps(no_unicode=PY2)))
3697 def pps(self, decode_path=(), no_unicode=False):
3701 hexenc(bytes(self)) if no_unicode else
3702 "".join(escape_control_unicode(c) for c in self.__unicode__())
3706 asn1_type_name=self.asn1_type_name,
3707 obj_name=self.__class__.__name__,
3708 decode_path=decode_path,
3710 optional=self.optional,
3711 default=self == self.default,
3712 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3713 expl=None if self._expl is None else tag_decode(self._expl),
3718 expl_offset=self.expl_offset if self.expled else None,
3719 expl_tlen=self.expl_tlen if self.expled else None,
3720 expl_llen=self.expl_llen if self.expled else None,
3721 expl_vlen=self.expl_vlen if self.expled else None,
3722 expl_lenindef=self.expl_lenindef,
3723 ber_encoded=self.ber_encoded,
3726 for pp in self.pps_lenindef(decode_path):
3730 class UTF8String(CommonString):
3732 tag_default = tag_encode(12)
3734 asn1_type_name = "UTF8String"
3737 class AllowableCharsMixin(object):
3739 def allowable_chars(self):
3741 return self._allowable_chars
3742 return frozenset(six_unichr(c) for c in self._allowable_chars)
3745 class NumericString(AllowableCharsMixin, CommonString):
3748 Its value is properly sanitized: only ASCII digits with spaces can
3751 >>> NumericString().allowable_chars
3752 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3755 tag_default = tag_encode(18)
3757 asn1_type_name = "NumericString"
3758 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3760 def _value_sanitize(self, value):
3761 value = super(NumericString, self)._value_sanitize(value)
3762 if not frozenset(value) <= self._allowable_chars:
3763 raise DecodeError("non-numeric value")
3767 class PrintableString(AllowableCharsMixin, CommonString):
3770 Its value is properly sanitized: see X.680 41.4 table 10.
3772 >>> PrintableString().allowable_chars
3773 frozenset([' ', "'", ..., 'z'])
3776 tag_default = tag_encode(19)
3778 asn1_type_name = "PrintableString"
3779 _allowable_chars = frozenset(
3780 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
3783 def _value_sanitize(self, value):
3784 value = super(PrintableString, self)._value_sanitize(value)
3785 if not frozenset(value) <= self._allowable_chars:
3786 raise DecodeError("non-printable value")
3790 class TeletexString(CommonString):
3792 tag_default = tag_encode(20)
3794 asn1_type_name = "TeletexString"
3797 class T61String(TeletexString):
3799 asn1_type_name = "T61String"
3802 class VideotexString(CommonString):
3804 tag_default = tag_encode(21)
3805 encoding = "iso-8859-1"
3806 asn1_type_name = "VideotexString"
3809 class IA5String(CommonString):
3811 tag_default = tag_encode(22)
3813 asn1_type_name = "IA5"
3816 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
3817 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
3818 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
3821 class UTCTime(CommonString):
3822 """``UTCTime`` datetime type
3824 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3825 UTCTime UTCTime 2017-09-30T22:07:50
3831 datetime.datetime(2017, 9, 30, 22, 7, 50)
3832 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
3833 datetime.datetime(1957, 9, 30, 22, 7, 50)
3837 BER encoding is unsupported.
3840 tag_default = tag_encode(23)
3842 asn1_type_name = "UTCTime"
3852 bounds=None, # dummy argument, workability for OctetString.decode
3855 :param value: set the value. Either datetime type, or
3856 :py:class:`pyderasn.UTCTime` object
3857 :param bytes impl: override default tag with ``IMPLICIT`` one
3858 :param bytes expl: override default tag with ``EXPLICIT`` one
3859 :param default: set default value. Type same as in ``value``
3860 :param bool optional: is object ``OPTIONAL`` in sequence
3862 super(UTCTime, self).__init__(
3863 None, None, impl, expl, default, optional, _decoded,
3866 if value is not None:
3867 self._value = self._value_sanitize(value)
3868 if default is not None:
3869 default = self._value_sanitize(default)
3870 self.default = self.__class__(
3875 if self._value is None:
3876 self._value = default
3878 def _strptime(self, value):
3879 # datetime.strptime's format: %y%m%d%H%M%SZ
3880 if len(value) != LEN_YYMMDDHHMMSSZ:
3881 raise ValueError("invalid UTCTime length")
3882 if value[-1] != "Z":
3883 raise ValueError("non UTC timezone")
3885 2000 + int(value[:2]), # %y
3886 int(value[2:4]), # %m
3887 int(value[4:6]), # %d
3888 int(value[6:8]), # %H
3889 int(value[8:10]), # %M
3890 int(value[10:12]), # %S
3893 def _value_sanitize(self, value):
3894 if isinstance(value, binary_type):
3896 value_decoded = value.decode("ascii")
3897 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3898 raise DecodeError("invalid UTCTime encoding: %r" % err)
3900 self._strptime(value_decoded)
3901 except (TypeError, ValueError) as err:
3902 raise DecodeError("invalid UTCTime format: %r" % err)
3904 if isinstance(value, self.__class__):
3906 if isinstance(value, datetime):
3907 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
3908 raise InvalidValueType((self.__class__, datetime))
3910 def __eq__(self, their):
3911 if isinstance(their, binary_type):
3912 return self._value == their
3913 if isinstance(their, datetime):
3914 return self.todatetime() == their
3915 if not isinstance(their, self.__class__):
3918 self._value == their._value and
3919 self.tag == their.tag and
3920 self._expl == their._expl
3923 def todatetime(self):
3924 """Convert to datetime
3928 Pay attention that UTCTime can not hold full year, so all years
3929 having < 50 years are treated as 20xx, 19xx otherwise, according
3930 to X.509 recomendation.
3932 value = self._strptime(self._value.decode("ascii"))
3933 year = value.year % 100
3935 year=(2000 + year) if year < 50 else (1900 + year),
3939 minute=value.minute,
3940 second=value.second,
3944 return pp_console_row(next(self.pps()))
3946 def pps(self, decode_path=()):
3949 asn1_type_name=self.asn1_type_name,
3950 obj_name=self.__class__.__name__,
3951 decode_path=decode_path,
3952 value=self.todatetime().isoformat() if self.ready else None,
3953 optional=self.optional,
3954 default=self == self.default,
3955 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3956 expl=None if self._expl is None else tag_decode(self._expl),
3961 expl_offset=self.expl_offset if self.expled else None,
3962 expl_tlen=self.expl_tlen if self.expled else None,
3963 expl_llen=self.expl_llen if self.expled else None,
3964 expl_vlen=self.expl_vlen if self.expled else None,
3965 expl_lenindef=self.expl_lenindef,
3966 ber_encoded=self.ber_encoded,
3969 for pp in self.pps_lenindef(decode_path):
3973 class GeneralizedTime(UTCTime):
3974 """``GeneralizedTime`` datetime type
3976 This type is similar to :py:class:`pyderasn.UTCTime`.
3978 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3979 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
3981 '20170930220750.000123Z'
3982 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
3983 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
3987 BER encoding is unsupported.
3991 Only microsecond fractions are supported.
3992 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
3993 higher precision values.
3996 tag_default = tag_encode(24)
3997 asn1_type_name = "GeneralizedTime"
3999 def _strptime(self, value):
4001 if l == LEN_YYYYMMDDHHMMSSZ:
4002 # datetime.strptime's format: %y%m%d%H%M%SZ
4003 if value[-1] != "Z":
4004 raise ValueError("non UTC timezone")
4006 int(value[:4]), # %Y
4007 int(value[4:6]), # %m
4008 int(value[6:8]), # %d
4009 int(value[8:10]), # %H
4010 int(value[10:12]), # %M
4011 int(value[12:14]), # %S
4013 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4014 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4015 if value[-1] != "Z":
4016 raise ValueError("non UTC timezone")
4017 if value[14] != ".":
4018 raise ValueError("no fractions separator")
4021 raise ValueError("trailing zero")
4024 raise ValueError("only microsecond fractions are supported")
4025 us = int(us + ("0" * (6 - us_len)))
4027 int(value[:4]), # %Y
4028 int(value[4:6]), # %m
4029 int(value[6:8]), # %d
4030 int(value[8:10]), # %H
4031 int(value[10:12]), # %M
4032 int(value[12:14]), # %S
4036 raise ValueError("invalid GeneralizedTime length")
4038 def _value_sanitize(self, value):
4039 if isinstance(value, binary_type):
4041 value_decoded = value.decode("ascii")
4042 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4043 raise DecodeError("invalid GeneralizedTime encoding: %r" % err)
4045 self._strptime(value_decoded)
4046 except (TypeError, ValueError) as err:
4048 "invalid GeneralizedTime format: %r" % err,
4049 klass=self.__class__,
4052 if isinstance(value, self.__class__):
4054 if isinstance(value, datetime):
4055 encoded = value.strftime("%Y%m%d%H%M%S")
4056 if value.microsecond > 0:
4057 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
4058 return (encoded + "Z").encode("ascii")
4059 raise InvalidValueType((self.__class__, datetime))
4061 def todatetime(self):
4062 return self._strptime(self._value.decode("ascii"))
4065 class GraphicString(CommonString):
4067 tag_default = tag_encode(25)
4068 encoding = "iso-8859-1"
4069 asn1_type_name = "GraphicString"
4072 class VisibleString(CommonString):
4074 tag_default = tag_encode(26)
4076 asn1_type_name = "VisibleString"
4079 class ISO646String(VisibleString):
4081 asn1_type_name = "ISO646String"
4084 class GeneralString(CommonString):
4086 tag_default = tag_encode(27)
4087 encoding = "iso-8859-1"
4088 asn1_type_name = "GeneralString"
4091 class UniversalString(CommonString):
4093 tag_default = tag_encode(28)
4094 encoding = "utf-32-be"
4095 asn1_type_name = "UniversalString"
4098 class BMPString(CommonString):
4100 tag_default = tag_encode(30)
4101 encoding = "utf-16-be"
4102 asn1_type_name = "BMPString"
4106 """``CHOICE`` special type
4110 class GeneralName(Choice):
4112 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4113 ("dNSName", IA5String(impl=tag_ctxp(2))),
4116 >>> gn = GeneralName()
4118 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4119 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4120 >>> gn["dNSName"] = IA5String("bar.baz")
4121 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4122 >>> gn["rfc822Name"]
4125 [2] IA5String IA5 bar.baz
4128 >>> gn.value == gn["dNSName"]
4131 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4133 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4134 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4136 __slots__ = ("specs",)
4138 asn1_type_name = "CHOICE"
4151 :param value: set the value. Either ``(choice, value)`` tuple, or
4152 :py:class:`pyderasn.Choice` object
4153 :param bytes impl: can not be set, do **not** use it
4154 :param bytes expl: override default tag with ``EXPLICIT`` one
4155 :param default: set default value. Type same as in ``value``
4156 :param bool optional: is object ``OPTIONAL`` in sequence
4158 if impl is not None:
4159 raise ValueError("no implicit tag allowed for CHOICE")
4160 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4162 schema = getattr(self, "schema", ())
4163 if len(schema) == 0:
4164 raise ValueError("schema must be specified")
4166 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4169 if value is not None:
4170 self._value = self._value_sanitize(value)
4171 if default is not None:
4172 default_value = self._value_sanitize(default)
4173 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4174 default_obj.specs = self.specs
4175 default_obj._value = default_value
4176 self.default = default_obj
4178 self._value = default_obj.copy()._value
4180 def _value_sanitize(self, value):
4181 if isinstance(value, tuple) and len(value) == 2:
4183 spec = self.specs.get(choice)
4185 raise ObjUnknown(choice)
4186 if not isinstance(obj, spec.__class__):
4187 raise InvalidValueType((spec,))
4188 return (choice, spec(obj))
4189 if isinstance(value, self.__class__):
4191 raise InvalidValueType((self.__class__, tuple))
4195 return self._value is not None and self._value[1].ready
4199 return self.expl_lenindef or (
4200 (self._value is not None) and
4201 self._value[1].bered
4205 obj = self.__class__(schema=self.specs)
4206 obj._expl = self._expl
4207 obj.default = self.default
4208 obj.optional = self.optional
4209 obj.offset = self.offset
4210 obj.llen = self.llen
4211 obj.vlen = self.vlen
4212 obj.expl_lenindef = self.expl_lenindef
4213 obj.lenindef = self.lenindef
4214 obj.ber_encoded = self.ber_encoded
4216 if value is not None:
4217 obj._value = (value[0], value[1].copy())
4220 def __eq__(self, their):
4221 if isinstance(their, tuple) and len(their) == 2:
4222 return self._value == their
4223 if not isinstance(their, self.__class__):
4226 self.specs == their.specs and
4227 self._value == their._value
4237 return self.__class__(
4240 expl=self._expl if expl is None else expl,
4241 default=self.default if default is None else default,
4242 optional=self.optional if optional is None else optional,
4247 self._assert_ready()
4248 return self._value[0]
4252 self._assert_ready()
4253 return self._value[1]
4255 def __getitem__(self, key):
4256 if key not in self.specs:
4257 raise ObjUnknown(key)
4258 if self._value is None:
4260 choice, value = self._value
4265 def __setitem__(self, key, value):
4266 spec = self.specs.get(key)
4268 raise ObjUnknown(key)
4269 if not isinstance(value, spec.__class__):
4270 raise InvalidValueType((spec.__class__,))
4271 self._value = (key, spec(value))
4279 return self._value[1].decoded if self.ready else False
4282 self._assert_ready()
4283 return self._value[1].encode()
4285 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4286 for choice, spec in iteritems(self.specs):
4287 sub_decode_path = decode_path + (choice,)
4293 decode_path=sub_decode_path,
4296 _ctx_immutable=False,
4303 klass=self.__class__,
4304 decode_path=decode_path,
4307 if tag_only: # pragma: no cover
4309 value, tail = spec.decode(
4313 decode_path=sub_decode_path,
4315 _ctx_immutable=False,
4317 obj = self.__class__(
4320 default=self.default,
4321 optional=self.optional,
4322 _decoded=(offset, 0, value.fulllen),
4324 obj._value = (choice, value)
4328 value = pp_console_row(next(self.pps()))
4330 value = "%s[%r]" % (value, self.value)
4333 def pps(self, decode_path=()):
4336 asn1_type_name=self.asn1_type_name,
4337 obj_name=self.__class__.__name__,
4338 decode_path=decode_path,
4339 value=self.choice if self.ready else None,
4340 optional=self.optional,
4341 default=self == self.default,
4342 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4343 expl=None if self._expl is None else tag_decode(self._expl),
4348 expl_lenindef=self.expl_lenindef,
4352 yield self.value.pps(decode_path=decode_path + (self.choice,))
4353 for pp in self.pps_lenindef(decode_path):
4357 class PrimitiveTypes(Choice):
4358 """Predefined ``CHOICE`` for all generic primitive types
4360 It could be useful for general decoding of some unspecified values:
4362 >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
4363 OCTET STRING 3 bytes 666f6f
4364 >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
4368 schema = tuple((klass.__name__, klass()) for klass in (
4393 """``ANY`` special type
4395 >>> Any(Integer(-123))
4397 >>> a = Any(OctetString(b"hello world").encode())
4398 ANY 040b68656c6c6f20776f726c64
4399 >>> hexenc(bytes(a))
4400 b'0x040x0bhello world'
4402 __slots__ = ("defined",)
4403 tag_default = tag_encode(0)
4404 asn1_type_name = "ANY"
4414 :param value: set the value. Either any kind of pyderasn's
4415 **ready** object, or bytes. Pay attention that
4416 **no** validation is performed is raw binary value
4418 :param bytes expl: override default tag with ``EXPLICIT`` one
4419 :param bool optional: is object ``OPTIONAL`` in sequence
4421 super(Any, self).__init__(None, expl, None, optional, _decoded)
4422 self._value = None if value is None else self._value_sanitize(value)
4425 def _value_sanitize(self, value):
4426 if isinstance(value, binary_type):
4428 if isinstance(value, self.__class__):
4430 if isinstance(value, Obj):
4431 return value.encode()
4432 raise InvalidValueType((self.__class__, Obj, binary_type))
4436 return self._value is not None
4440 if self.expl_lenindef or self.lenindef:
4442 if self.defined is None:
4444 return self.defined[1].bered
4447 obj = self.__class__()
4448 obj._value = self._value
4450 obj._expl = self._expl
4451 obj.optional = self.optional
4452 obj.offset = self.offset
4453 obj.llen = self.llen
4454 obj.vlen = self.vlen
4455 obj.expl_lenindef = self.expl_lenindef
4456 obj.lenindef = self.lenindef
4457 obj.ber_encoded = self.ber_encoded
4460 def __eq__(self, their):
4461 if isinstance(their, binary_type):
4462 return self._value == their
4463 if issubclass(their.__class__, Any):
4464 return self._value == their._value
4473 return self.__class__(
4475 expl=self._expl if expl is None else expl,
4476 optional=self.optional if optional is None else optional,
4479 def __bytes__(self):
4480 self._assert_ready()
4488 self._assert_ready()
4491 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4493 t, tlen, lv = tag_strip(tlv)
4494 except DecodeError as err:
4495 raise err.__class__(
4497 klass=self.__class__,
4498 decode_path=decode_path,
4502 l, llen, v = len_decode(lv)
4503 except LenIndefForm as err:
4504 if not ctx.get("bered", False):
4505 raise err.__class__(
4507 klass=self.__class__,
4508 decode_path=decode_path,
4511 llen, vlen, v = 1, 0, lv[1:]
4512 sub_offset = offset + tlen + llen
4514 while v[:EOC_LEN].tobytes() != EOC:
4515 chunk, v = Any().decode(
4518 decode_path=decode_path + (str(chunk_i),),
4521 _ctx_immutable=False,
4523 vlen += chunk.tlvlen
4524 sub_offset += chunk.tlvlen
4526 tlvlen = tlen + llen + vlen + EOC_LEN
4527 obj = self.__class__(
4528 value=tlv[:tlvlen].tobytes(),
4530 optional=self.optional,
4531 _decoded=(offset, 0, tlvlen),
4535 return obj, v[EOC_LEN:]
4536 except DecodeError as err:
4537 raise err.__class__(
4539 klass=self.__class__,
4540 decode_path=decode_path,
4544 raise NotEnoughData(
4545 "encoded length is longer than data",
4546 klass=self.__class__,
4547 decode_path=decode_path,
4550 tlvlen = tlen + llen + l
4551 v, tail = tlv[:tlvlen], v[l:]
4552 obj = self.__class__(
4555 optional=self.optional,
4556 _decoded=(offset, 0, tlvlen),
4562 return pp_console_row(next(self.pps()))
4564 def pps(self, decode_path=()):
4567 asn1_type_name=self.asn1_type_name,
4568 obj_name=self.__class__.__name__,
4569 decode_path=decode_path,
4570 blob=self._value if self.ready else None,
4571 optional=self.optional,
4572 default=self == self.default,
4573 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4574 expl=None if self._expl is None else tag_decode(self._expl),
4579 expl_offset=self.expl_offset if self.expled else None,
4580 expl_tlen=self.expl_tlen if self.expled else None,
4581 expl_llen=self.expl_llen if self.expled else None,
4582 expl_vlen=self.expl_vlen if self.expled else None,
4583 expl_lenindef=self.expl_lenindef,
4584 lenindef=self.lenindef,
4587 defined_by, defined = self.defined or (None, None)
4588 if defined_by is not None:
4590 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4592 for pp in self.pps_lenindef(decode_path):
4596 ########################################################################
4597 # ASN.1 constructed types
4598 ########################################################################
4600 def get_def_by_path(defines_by_path, sub_decode_path):
4601 """Get define by decode path
4603 for path, define in defines_by_path:
4604 if len(path) != len(sub_decode_path):
4606 for p1, p2 in zip(path, sub_decode_path):
4607 if (p1 != any) and (p1 != p2):
4613 def abs_decode_path(decode_path, rel_path):
4614 """Create an absolute decode path from current and relative ones
4616 :param decode_path: current decode path, starting point. Tuple of strings
4617 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4618 If first tuple's element is "/", then treat it as
4619 an absolute path, ignoring ``decode_path`` as
4620 starting point. Also this tuple can contain ".."
4621 elements, stripping the leading element from
4624 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4625 ("foo", "bar", "baz", "whatever")
4626 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4628 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4631 if rel_path[0] == "/":
4633 if rel_path[0] == "..":
4634 return abs_decode_path(decode_path[:-1], rel_path[1:])
4635 return decode_path + rel_path
4638 class Sequence(Obj):
4639 """``SEQUENCE`` structure type
4641 You have to make specification of sequence::
4643 class Extension(Sequence):
4645 ("extnID", ObjectIdentifier()),
4646 ("critical", Boolean(default=False)),
4647 ("extnValue", OctetString()),
4650 Then, you can work with it as with dictionary.
4652 >>> ext = Extension()
4653 >>> Extension().specs
4655 ('extnID', OBJECT IDENTIFIER),
4656 ('critical', BOOLEAN False OPTIONAL DEFAULT),
4657 ('extnValue', OCTET STRING),
4659 >>> ext["extnID"] = "1.2.3"
4660 Traceback (most recent call last):
4661 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
4662 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
4664 You can determine if sequence is ready to be encoded:
4669 Traceback (most recent call last):
4670 pyderasn.ObjNotReady: object is not ready: extnValue
4671 >>> ext["extnValue"] = OctetString(b"foobar")
4675 Value you want to assign, must have the same **type** as in
4676 corresponding specification, but it can have different tags,
4677 optional/default attributes -- they will be taken from specification
4680 class TBSCertificate(Sequence):
4682 ("version", Version(expl=tag_ctxc(0), default="v1")),
4685 >>> tbs = TBSCertificate()
4686 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
4688 Assign ``None`` to remove value from sequence.
4690 You can set values in Sequence during its initialization:
4692 >>> AlgorithmIdentifier((
4693 ("algorithm", ObjectIdentifier("1.2.3")),
4694 ("parameters", Any(Null()))
4696 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
4698 You can determine if value exists/set in the sequence and take its value:
4700 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
4703 OBJECT IDENTIFIER 1.2.3
4705 But pay attention that if value has default, then it won't be (not
4706 in) in the sequence (because ``DEFAULT`` must not be encoded in
4707 DER), but you can read its value:
4709 >>> "critical" in ext, ext["critical"]
4710 (False, BOOLEAN False)
4711 >>> ext["critical"] = Boolean(True)
4712 >>> "critical" in ext, ext["critical"]
4713 (True, BOOLEAN True)
4715 All defaulted values are always optional.
4717 .. _allow_default_values_ctx:
4719 DER prohibits default value encoding and will raise an error if
4720 default value is unexpectedly met during decode.
4721 If :ref:`bered <bered_ctx>` context option is set, then no error
4722 will be raised, but ``bered`` attribute set. You can disable strict
4723 defaulted values existence validation by setting
4724 ``"allow_default_values": True`` :ref:`context <ctx>` option.
4726 Two sequences are equal if they have equal specification (schema),
4727 implicit/explicit tagging and the same values.
4729 __slots__ = ("specs",)
4730 tag_default = tag_encode(form=TagFormConstructed, num=16)
4731 asn1_type_name = "SEQUENCE"
4743 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
4745 schema = getattr(self, "schema", ())
4747 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4750 if value is not None:
4751 if issubclass(value.__class__, Sequence):
4752 self._value = value._value
4753 elif hasattr(value, "__iter__"):
4754 for seq_key, seq_value in value:
4755 self[seq_key] = seq_value
4757 raise InvalidValueType((Sequence,))
4758 if default is not None:
4759 if not issubclass(default.__class__, Sequence):
4760 raise InvalidValueType((Sequence,))
4761 default_value = default._value
4762 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4763 default_obj.specs = self.specs
4764 default_obj._value = default_value
4765 self.default = default_obj
4767 self._value = default_obj.copy()._value
4771 for name, spec in iteritems(self.specs):
4772 value = self._value.get(name)
4783 if self.expl_lenindef or self.lenindef or self.ber_encoded:
4785 return any(value.bered for value in itervalues(self._value))
4788 obj = self.__class__(schema=self.specs)
4790 obj._expl = self._expl
4791 obj.default = self.default
4792 obj.optional = self.optional
4793 obj.offset = self.offset
4794 obj.llen = self.llen
4795 obj.vlen = self.vlen
4796 obj.expl_lenindef = self.expl_lenindef
4797 obj.lenindef = self.lenindef
4798 obj.ber_encoded = self.ber_encoded
4799 obj._value = {k: v.copy() for k, v in iteritems(self._value)}
4802 def __eq__(self, their):
4803 if not isinstance(their, self.__class__):
4806 self.specs == their.specs and
4807 self.tag == their.tag and
4808 self._expl == their._expl and
4809 self._value == their._value
4820 return self.__class__(
4823 impl=self.tag if impl is None else impl,
4824 expl=self._expl if expl is None else expl,
4825 default=self.default if default is None else default,
4826 optional=self.optional if optional is None else optional,
4829 def __contains__(self, key):
4830 return key in self._value
4832 def __setitem__(self, key, value):
4833 spec = self.specs.get(key)
4835 raise ObjUnknown(key)
4837 self._value.pop(key, None)
4839 if not isinstance(value, spec.__class__):
4840 raise InvalidValueType((spec.__class__,))
4841 value = spec(value=value)
4842 if spec.default is not None and value == spec.default:
4843 self._value.pop(key, None)
4845 self._value[key] = value
4847 def __getitem__(self, key):
4848 value = self._value.get(key)
4849 if value is not None:
4851 spec = self.specs.get(key)
4853 raise ObjUnknown(key)
4854 if spec.default is not None:
4858 def _encoded_values(self):
4860 for name, spec in iteritems(self.specs):
4861 value = self._value.get(name)
4865 raise ObjNotReady(name)
4866 raws.append(value.encode())
4870 v = b"".join(self._encoded_values())
4871 return b"".join((self.tag, len_encode(len(v)), v))
4873 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4875 t, tlen, lv = tag_strip(tlv)
4876 except DecodeError as err:
4877 raise err.__class__(
4879 klass=self.__class__,
4880 decode_path=decode_path,
4885 klass=self.__class__,
4886 decode_path=decode_path,
4889 if tag_only: # pragma: no cover
4892 ctx_bered = ctx.get("bered", False)
4894 l, llen, v = len_decode(lv)
4895 except LenIndefForm as err:
4897 raise err.__class__(
4899 klass=self.__class__,
4900 decode_path=decode_path,
4903 l, llen, v = 0, 1, lv[1:]
4905 except DecodeError as err:
4906 raise err.__class__(
4908 klass=self.__class__,
4909 decode_path=decode_path,
4913 raise NotEnoughData(
4914 "encoded length is longer than data",
4915 klass=self.__class__,
4916 decode_path=decode_path,
4920 v, tail = v[:l], v[l:]
4922 sub_offset = offset + tlen + llen
4925 ctx_allow_default_values = ctx.get("allow_default_values", False)
4926 for name, spec in iteritems(self.specs):
4927 if spec.optional and (
4928 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
4932 sub_decode_path = decode_path + (name,)
4934 value, v_tail = spec.decode(
4938 decode_path=sub_decode_path,
4940 _ctx_immutable=False,
4942 except TagMismatch as err:
4943 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
4947 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
4948 if defined is not None:
4949 defined_by, defined_spec = defined
4950 if issubclass(value.__class__, SequenceOf):
4951 for i, _value in enumerate(value):
4952 sub_sub_decode_path = sub_decode_path + (
4954 DecodePathDefBy(defined_by),
4956 defined_value, defined_tail = defined_spec.decode(
4957 memoryview(bytes(_value)),
4959 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4960 if value.expled else (value.tlen + value.llen)
4963 decode_path=sub_sub_decode_path,
4965 _ctx_immutable=False,
4967 if len(defined_tail) > 0:
4970 klass=self.__class__,
4971 decode_path=sub_sub_decode_path,
4974 _value.defined = (defined_by, defined_value)
4976 defined_value, defined_tail = defined_spec.decode(
4977 memoryview(bytes(value)),
4979 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4980 if value.expled else (value.tlen + value.llen)
4983 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4985 _ctx_immutable=False,
4987 if len(defined_tail) > 0:
4990 klass=self.__class__,
4991 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4994 value.defined = (defined_by, defined_value)
4996 value_len = value.fulllen
4998 sub_offset += value_len
5000 if spec.default is not None and value == spec.default:
5001 if ctx_bered or ctx_allow_default_values:
5005 "DEFAULT value met",
5006 klass=self.__class__,
5007 decode_path=sub_decode_path,
5010 values[name] = value
5012 spec_defines = getattr(spec, "defines", ())
5013 if len(spec_defines) == 0:
5014 defines_by_path = ctx.get("defines_by_path", ())
5015 if len(defines_by_path) > 0:
5016 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5017 if spec_defines is not None and len(spec_defines) > 0:
5018 for rel_path, schema in spec_defines:
5019 defined = schema.get(value, None)
5020 if defined is not None:
5021 ctx.setdefault("_defines", []).append((
5022 abs_decode_path(sub_decode_path[:-1], rel_path),
5026 if v[:EOC_LEN].tobytes() != EOC:
5029 klass=self.__class__,
5030 decode_path=decode_path,
5038 klass=self.__class__,
5039 decode_path=decode_path,
5042 obj = self.__class__(
5046 default=self.default,
5047 optional=self.optional,
5048 _decoded=(offset, llen, vlen),
5051 obj.lenindef = lenindef
5052 obj.ber_encoded = ber_encoded
5056 value = pp_console_row(next(self.pps()))
5058 for name in self.specs:
5059 _value = self._value.get(name)
5062 cols.append("%s: %s" % (name, repr(_value)))
5063 return "%s[%s]" % (value, "; ".join(cols))
5065 def pps(self, decode_path=()):
5068 asn1_type_name=self.asn1_type_name,
5069 obj_name=self.__class__.__name__,
5070 decode_path=decode_path,
5071 optional=self.optional,
5072 default=self == self.default,
5073 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5074 expl=None if self._expl is None else tag_decode(self._expl),
5079 expl_offset=self.expl_offset if self.expled else None,
5080 expl_tlen=self.expl_tlen if self.expled else None,
5081 expl_llen=self.expl_llen if self.expled else None,
5082 expl_vlen=self.expl_vlen if self.expled else None,
5083 expl_lenindef=self.expl_lenindef,
5084 lenindef=self.lenindef,
5085 ber_encoded=self.ber_encoded,
5088 for name in self.specs:
5089 value = self._value.get(name)
5092 yield value.pps(decode_path=decode_path + (name,))
5093 for pp in self.pps_lenindef(decode_path):
5097 class Set(Sequence):
5098 """``SET`` structure type
5100 Its usage is identical to :py:class:`pyderasn.Sequence`.
5102 .. _allow_unordered_set_ctx:
5104 DER prohibits unordered values encoding and will raise an error
5105 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5106 then no error will occure. Also you can disable strict values
5107 ordering check by setting ``"allow_unordered_set": True``
5108 :ref:`context <ctx>` option.
5111 tag_default = tag_encode(form=TagFormConstructed, num=17)
5112 asn1_type_name = "SET"
5115 raws = self._encoded_values()
5118 return b"".join((self.tag, len_encode(len(v)), v))
5120 def _specs_items(self):
5121 return iteritems(self.specs)
5123 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5125 t, tlen, lv = tag_strip(tlv)
5126 except DecodeError as err:
5127 raise err.__class__(
5129 klass=self.__class__,
5130 decode_path=decode_path,
5135 klass=self.__class__,
5136 decode_path=decode_path,
5142 ctx_bered = ctx.get("bered", False)
5144 l, llen, v = len_decode(lv)
5145 except LenIndefForm as err:
5147 raise err.__class__(
5149 klass=self.__class__,
5150 decode_path=decode_path,
5153 l, llen, v = 0, 1, lv[1:]
5155 except DecodeError as err:
5156 raise err.__class__(
5158 klass=self.__class__,
5159 decode_path=decode_path,
5163 raise NotEnoughData(
5164 "encoded length is longer than data",
5165 klass=self.__class__,
5169 v, tail = v[:l], v[l:]
5171 sub_offset = offset + tlen + llen
5174 ctx_allow_default_values = ctx.get("allow_default_values", False)
5175 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5176 value_prev = memoryview(v[:0])
5179 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5181 for name, spec in self._specs_items():
5182 sub_decode_path = decode_path + (name,)
5188 decode_path=sub_decode_path,
5191 _ctx_immutable=False,
5198 klass=self.__class__,
5199 decode_path=decode_path,
5202 value, v_tail = spec.decode(
5206 decode_path=sub_decode_path,
5208 _ctx_immutable=False,
5210 value_len = value.fulllen
5211 if value_prev.tobytes() > v[:value_len].tobytes():
5212 if ctx_bered or ctx_allow_unordered_set:
5216 "unordered " + self.asn1_type_name,
5217 klass=self.__class__,
5218 decode_path=sub_decode_path,
5221 if spec.default is None or value != spec.default:
5223 elif ctx_bered or ctx_allow_default_values:
5227 "DEFAULT value met",
5228 klass=self.__class__,
5229 decode_path=sub_decode_path,
5232 values[name] = value
5233 value_prev = v[:value_len]
5234 sub_offset += value_len
5237 obj = self.__class__(
5241 default=self.default,
5242 optional=self.optional,
5243 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5246 if v[:EOC_LEN].tobytes() != EOC:
5249 klass=self.__class__,
5250 decode_path=decode_path,
5258 "not all values are ready",
5259 klass=self.__class__,
5260 decode_path=decode_path,
5263 obj.ber_encoded = ber_encoded
5267 class SequenceOf(Obj):
5268 """``SEQUENCE OF`` sequence type
5270 For that kind of type you must specify the object it will carry on
5271 (bounds are for example here, not required)::
5273 class Ints(SequenceOf):
5278 >>> ints.append(Integer(123))
5279 >>> ints.append(Integer(234))
5281 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5282 >>> [int(i) for i in ints]
5284 >>> ints.append(Integer(345))
5285 Traceback (most recent call last):
5286 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5289 >>> ints[1] = Integer(345)
5291 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5293 Also you can initialize sequence with preinitialized values:
5295 >>> ints = Ints([Integer(123), Integer(234)])
5297 __slots__ = ("spec", "_bound_min", "_bound_max")
5298 tag_default = tag_encode(form=TagFormConstructed, num=16)
5299 asn1_type_name = "SEQUENCE OF"
5312 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5314 schema = getattr(self, "schema", None)
5316 raise ValueError("schema must be specified")
5318 self._bound_min, self._bound_max = getattr(
5322 ) if bounds is None else bounds
5324 if value is not None:
5325 self._value = self._value_sanitize(value)
5326 if default is not None:
5327 default_value = self._value_sanitize(default)
5328 default_obj = self.__class__(
5333 default_obj._value = default_value
5334 self.default = default_obj
5336 self._value = default_obj.copy()._value
5338 def _value_sanitize(self, value):
5339 if issubclass(value.__class__, SequenceOf):
5340 value = value._value
5341 elif hasattr(value, "__iter__"):
5344 raise InvalidValueType((self.__class__, iter))
5345 if not self._bound_min <= len(value) <= self._bound_max:
5346 raise BoundsError(self._bound_min, len(value), self._bound_max)
5348 if not isinstance(v, self.spec.__class__):
5349 raise InvalidValueType((self.spec.__class__,))
5354 return all(v.ready for v in self._value)
5358 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5360 return any(v.bered for v in self._value)
5363 obj = self.__class__(schema=self.spec)
5364 obj._bound_min = self._bound_min
5365 obj._bound_max = self._bound_max
5367 obj._expl = self._expl
5368 obj.default = self.default
5369 obj.optional = self.optional
5370 obj.offset = self.offset
5371 obj.llen = self.llen
5372 obj.vlen = self.vlen
5373 obj.expl_lenindef = self.expl_lenindef
5374 obj.lenindef = self.lenindef
5375 obj.ber_encoded = self.ber_encoded
5376 obj._value = [v.copy() for v in self._value]
5379 def __eq__(self, their):
5380 if isinstance(their, self.__class__):
5382 self.spec == their.spec and
5383 self.tag == their.tag and
5384 self._expl == their._expl and
5385 self._value == their._value
5387 if hasattr(their, "__iter__"):
5388 return self._value == list(their)
5400 return self.__class__(
5404 (self._bound_min, self._bound_max)
5405 if bounds is None else bounds
5407 impl=self.tag if impl is None else impl,
5408 expl=self._expl if expl is None else expl,
5409 default=self.default if default is None else default,
5410 optional=self.optional if optional is None else optional,
5413 def __contains__(self, key):
5414 return key in self._value
5416 def append(self, value):
5417 if not isinstance(value, self.spec.__class__):
5418 raise InvalidValueType((self.spec.__class__,))
5419 if len(self._value) + 1 > self._bound_max:
5422 len(self._value) + 1,
5425 self._value.append(value)
5428 self._assert_ready()
5429 return iter(self._value)
5432 self._assert_ready()
5433 return len(self._value)
5435 def __setitem__(self, key, value):
5436 if not isinstance(value, self.spec.__class__):
5437 raise InvalidValueType((self.spec.__class__,))
5438 self._value[key] = self.spec(value=value)
5440 def __getitem__(self, key):
5441 return self._value[key]
5443 def _encoded_values(self):
5444 return [v.encode() for v in self._value]
5447 v = b"".join(self._encoded_values())
5448 return b"".join((self.tag, len_encode(len(v)), v))
5450 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5452 t, tlen, lv = tag_strip(tlv)
5453 except DecodeError as err:
5454 raise err.__class__(
5456 klass=self.__class__,
5457 decode_path=decode_path,
5462 klass=self.__class__,
5463 decode_path=decode_path,
5469 ctx_bered = ctx.get("bered", False)
5471 l, llen, v = len_decode(lv)
5472 except LenIndefForm as err:
5474 raise err.__class__(
5476 klass=self.__class__,
5477 decode_path=decode_path,
5480 l, llen, v = 0, 1, lv[1:]
5482 except DecodeError as err:
5483 raise err.__class__(
5485 klass=self.__class__,
5486 decode_path=decode_path,
5490 raise NotEnoughData(
5491 "encoded length is longer than data",
5492 klass=self.__class__,
5493 decode_path=decode_path,
5497 v, tail = v[:l], v[l:]
5499 sub_offset = offset + tlen + llen
5501 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5502 value_prev = memoryview(v[:0])
5506 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5508 sub_decode_path = decode_path + (str(len(_value)),)
5509 value, v_tail = spec.decode(
5513 decode_path=sub_decode_path,
5515 _ctx_immutable=False,
5517 value_len = value.fulllen
5519 if value_prev.tobytes() > v[:value_len].tobytes():
5520 if ctx_bered or ctx_allow_unordered_set:
5524 "unordered " + self.asn1_type_name,
5525 klass=self.__class__,
5526 decode_path=sub_decode_path,
5529 value_prev = v[:value_len]
5530 _value.append(value)
5531 sub_offset += value_len
5535 obj = self.__class__(
5538 bounds=(self._bound_min, self._bound_max),
5541 default=self.default,
5542 optional=self.optional,
5543 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5545 except BoundsError as err:
5548 klass=self.__class__,
5549 decode_path=decode_path,
5553 if v[:EOC_LEN].tobytes() != EOC:
5556 klass=self.__class__,
5557 decode_path=decode_path,
5562 obj.ber_encoded = ber_encoded
5567 pp_console_row(next(self.pps())),
5568 ", ".join(repr(v) for v in self._value),
5571 def pps(self, decode_path=()):
5574 asn1_type_name=self.asn1_type_name,
5575 obj_name=self.__class__.__name__,
5576 decode_path=decode_path,
5577 optional=self.optional,
5578 default=self == self.default,
5579 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5580 expl=None if self._expl is None else tag_decode(self._expl),
5585 expl_offset=self.expl_offset if self.expled else None,
5586 expl_tlen=self.expl_tlen if self.expled else None,
5587 expl_llen=self.expl_llen if self.expled else None,
5588 expl_vlen=self.expl_vlen if self.expled else None,
5589 expl_lenindef=self.expl_lenindef,
5590 lenindef=self.lenindef,
5591 ber_encoded=self.ber_encoded,
5594 for i, value in enumerate(self._value):
5595 yield value.pps(decode_path=decode_path + (str(i),))
5596 for pp in self.pps_lenindef(decode_path):
5600 class SetOf(SequenceOf):
5601 """``SET OF`` sequence type
5603 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
5606 tag_default = tag_encode(form=TagFormConstructed, num=17)
5607 asn1_type_name = "SET OF"
5610 raws = self._encoded_values()
5613 return b"".join((self.tag, len_encode(len(v)), v))
5615 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5616 return super(SetOf, self)._decode(
5622 ordering_check=True,
5626 def obj_by_path(pypath): # pragma: no cover
5627 """Import object specified as string Python path
5629 Modules must be separated from classes/functions with ``:``.
5631 >>> obj_by_path("foo.bar:Baz")
5632 <class 'foo.bar.Baz'>
5633 >>> obj_by_path("foo.bar:Baz.boo")
5634 <classmethod 'foo.bar.Baz.boo'>
5636 mod, objs = pypath.rsplit(":", 1)
5637 from importlib import import_module
5638 obj = import_module(mod)
5639 for obj_name in objs.split("."):
5640 obj = getattr(obj, obj_name)
5644 def generic_decoder(): # pragma: no cover
5645 # All of this below is a big hack with self references
5646 choice = PrimitiveTypes()
5647 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
5648 choice.specs["SetOf"] = SetOf(schema=choice)
5649 for i in six_xrange(31):
5650 choice.specs["SequenceOf%d" % i] = SequenceOf(
5654 choice.specs["Any"] = Any()
5656 # Class name equals to type name, to omit it from output
5657 class SEQUENCEOF(SequenceOf):
5665 with_decode_path=False,
5666 decode_path_only=(),
5668 def _pprint_pps(pps):
5670 if hasattr(pp, "_fields"):
5672 decode_path_only != () and
5673 pp.decode_path[:len(decode_path_only)] != decode_path_only
5676 if pp.asn1_type_name == Choice.asn1_type_name:
5678 pp_kwargs = pp._asdict()
5679 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
5680 pp = _pp(**pp_kwargs)
5681 yield pp_console_row(
5686 with_colours=with_colours,
5687 with_decode_path=with_decode_path,
5688 decode_path_len_decrease=len(decode_path_only),
5690 for row in pp_console_blob(
5692 decode_path_len_decrease=len(decode_path_only),
5696 for row in _pprint_pps(pp):
5698 return "\n".join(_pprint_pps(obj.pps()))
5699 return SEQUENCEOF(), pprint_any
5702 def main(): # pragma: no cover
5704 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
5705 parser.add_argument(
5709 help="Skip that number of bytes from the beginning",
5711 parser.add_argument(
5713 help="Python paths to dictionary with OIDs, comma separated",
5715 parser.add_argument(
5717 help="Python path to schema definition to use",
5719 parser.add_argument(
5720 "--defines-by-path",
5721 help="Python path to decoder's defines_by_path",
5723 parser.add_argument(
5725 action="store_true",
5726 help="Disallow BER encoding",
5728 parser.add_argument(
5729 "--print-decode-path",
5730 action="store_true",
5731 help="Print decode paths",
5733 parser.add_argument(
5734 "--decode-path-only",
5735 help="Print only specified decode path",
5737 parser.add_argument(
5739 action="store_true",
5740 help="Allow explicit tag out-of-bound",
5742 parser.add_argument(
5744 type=argparse.FileType("rb"),
5745 help="Path to DER file you want to decode",
5747 args = parser.parse_args()
5748 args.DERFile.seek(args.skip)
5749 der = memoryview(args.DERFile.read())
5750 args.DERFile.close()
5752 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
5753 if args.oids else ()
5756 schema = obj_by_path(args.schema)
5757 from functools import partial
5758 pprinter = partial(pprint, big_blobs=True)
5760 schema, pprinter = generic_decoder()
5762 "bered": not args.nobered,
5763 "allow_expl_oob": args.allow_expl_oob,
5765 if args.defines_by_path is not None:
5766 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
5767 obj, tail = schema().decode(der, ctx=ctx)
5771 with_colours=environ.get("NO_COLOR") is None,
5772 with_decode_path=args.print_decode_path,
5774 () if args.decode_path_only is None else
5775 tuple(args.decode_path_only.split(":"))
5779 print("\nTrailing data: %s" % hexenc(tail))
5782 if __name__ == "__main__":