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
659 from six import add_metaclass
660 from six import binary_type
661 from six import byte2int
662 from six import indexbytes
663 from six import int2byte
664 from six import integer_types
665 from six import iterbytes
666 from six import iteritems
667 from six import itervalues
669 from six import string_types
670 from six import text_type
671 from six import unichr as six_unichr
672 from six.moves import xrange as six_xrange
676 from termcolor import colored
677 except ImportError: # pragma: no cover
678 def colored(what, *args, **kwargs):
724 "TagClassApplication",
728 "TagFormConstructed",
739 TagClassUniversal = 0
740 TagClassApplication = 1 << 6
741 TagClassContext = 1 << 7
742 TagClassPrivate = 1 << 6 | 1 << 7
744 TagFormConstructed = 1 << 5
747 TagClassApplication: "APPLICATION ",
748 TagClassPrivate: "PRIVATE ",
749 TagClassUniversal: "UNIV ",
753 LENINDEF = b"\x80" # length indefinite mark
754 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
757 ########################################################################
759 ########################################################################
761 class ASN1Error(ValueError):
765 class DecodeError(ASN1Error):
766 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
768 :param str msg: reason of decode failing
769 :param klass: optional exact DecodeError inherited class (like
770 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
771 :py:exc:`InvalidLength`)
772 :param decode_path: tuple of strings. It contains human
773 readable names of the fields through which
774 decoding process has passed
775 :param int offset: binary offset where failure happened
777 super(DecodeError, self).__init__()
780 self.decode_path = decode_path
786 "" if self.klass is None else self.klass.__name__,
788 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
789 if len(self.decode_path) > 0 else ""
791 ("(at %d)" % self.offset) if self.offset > 0 else "",
797 return "%s(%s)" % (self.__class__.__name__, self)
800 class NotEnoughData(DecodeError):
804 class ExceedingData(ASN1Error):
805 def __init__(self, nbytes):
806 super(ExceedingData, self).__init__()
810 return "%d trailing bytes" % self.nbytes
813 return "%s(%s)" % (self.__class__.__name__, self)
816 class LenIndefForm(DecodeError):
820 class TagMismatch(DecodeError):
824 class InvalidLength(DecodeError):
828 class InvalidOID(DecodeError):
832 class ObjUnknown(ASN1Error):
833 def __init__(self, name):
834 super(ObjUnknown, self).__init__()
838 return "object is unknown: %s" % self.name
841 return "%s(%s)" % (self.__class__.__name__, self)
844 class ObjNotReady(ASN1Error):
845 def __init__(self, name):
846 super(ObjNotReady, self).__init__()
850 return "object is not ready: %s" % self.name
853 return "%s(%s)" % (self.__class__.__name__, self)
856 class InvalidValueType(ASN1Error):
857 def __init__(self, expected_types):
858 super(InvalidValueType, self).__init__()
859 self.expected_types = expected_types
862 return "invalid value type, expected: %s" % ", ".join(
863 [repr(t) for t in self.expected_types]
867 return "%s(%s)" % (self.__class__.__name__, self)
870 class BoundsError(ASN1Error):
871 def __init__(self, bound_min, value, bound_max):
872 super(BoundsError, self).__init__()
873 self.bound_min = bound_min
875 self.bound_max = bound_max
878 return "unsatisfied bounds: %s <= %s <= %s" % (
885 return "%s(%s)" % (self.__class__.__name__, self)
888 ########################################################################
890 ########################################################################
892 _hexdecoder = getdecoder("hex")
893 _hexencoder = getencoder("hex")
897 """Binary data to hexadecimal string convert
899 return _hexdecoder(data)[0]
903 """Hexadecimal string to binary data convert
905 return _hexencoder(data)[0].decode("ascii")
908 def int_bytes_len(num, byte_len=8):
911 return int(ceil(float(num.bit_length()) / byte_len))
914 def zero_ended_encode(num):
915 octets = bytearray(int_bytes_len(num, 7))
917 octets[i] = num & 0x7F
921 octets[i] = 0x80 | (num & 0x7F)
927 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
928 """Encode tag to binary form
930 :param int num: tag's number
931 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
932 :py:data:`pyderasn.TagClassContext`,
933 :py:data:`pyderasn.TagClassApplication`,
934 :py:data:`pyderasn.TagClassPrivate`)
935 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
936 :py:data:`pyderasn.TagFormConstructed`)
940 return int2byte(klass | form | num)
941 # [XX|X|11111][1.......][1.......] ... [0.......]
942 return int2byte(klass | form | 31) + zero_ended_encode(num)
946 """Decode tag from binary form
950 No validation is performed, assuming that it has already passed.
952 It returns tuple with three integers, as
953 :py:func:`pyderasn.tag_encode` accepts.
955 first_octet = byte2int(tag)
956 klass = first_octet & 0xC0
957 form = first_octet & 0x20
958 if first_octet & 0x1F < 0x1F:
959 return (klass, form, first_octet & 0x1F)
961 for octet in iterbytes(tag[1:]):
964 return (klass, form, num)
968 """Create CONTEXT PRIMITIVE tag
970 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
974 """Create CONTEXT CONSTRUCTED tag
976 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
980 """Take off tag from the data
982 :returns: (encoded tag, tag length, remaining data)
985 raise NotEnoughData("no data at all")
986 if byte2int(data) & 0x1F < 31:
987 return data[:1], 1, data[1:]
992 raise DecodeError("unfinished tag")
993 if indexbytes(data, i) & 0x80 == 0:
996 return data[:i], i, data[i:]
1002 octets = bytearray(int_bytes_len(l) + 1)
1003 octets[0] = 0x80 | (len(octets) - 1)
1004 for i in six_xrange(len(octets) - 1, 0, -1):
1005 octets[i] = l & 0xFF
1007 return bytes(octets)
1010 def len_decode(data):
1013 :returns: (decoded length, length's length, remaining data)
1014 :raises LenIndefForm: if indefinite form encoding is met
1017 raise NotEnoughData("no data at all")
1018 first_octet = byte2int(data)
1019 if first_octet & 0x80 == 0:
1020 return first_octet, 1, data[1:]
1021 octets_num = first_octet & 0x7F
1022 if octets_num + 1 > len(data):
1023 raise NotEnoughData("encoded length is longer than data")
1025 raise LenIndefForm()
1026 if byte2int(data[1:]) == 0:
1027 raise DecodeError("leading zeros")
1029 for v in iterbytes(data[1:1 + octets_num]):
1032 raise DecodeError("long form instead of short one")
1033 return l, 1 + octets_num, data[1 + octets_num:]
1036 ########################################################################
1038 ########################################################################
1040 class AutoAddSlots(type):
1041 def __new__(cls, name, bases, _dict):
1042 _dict["__slots__"] = _dict.get("__slots__", ())
1043 return type.__new__(cls, name, bases, _dict)
1046 @add_metaclass(AutoAddSlots)
1048 """Common ASN.1 object class
1050 All ASN.1 types are inherited from it. It has metaclass that
1051 automatically adds ``__slots__`` to all inherited classes.
1075 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1076 self._expl = getattr(self, "expl", None) if expl is None else expl
1077 if self.tag != self.tag_default and self._expl is not None:
1078 raise ValueError("implicit and explicit tags can not be set simultaneously")
1079 if default is not None:
1081 self.optional = optional
1082 self.offset, self.llen, self.vlen = _decoded
1084 self.expl_lenindef = False
1085 self.lenindef = False
1086 self.ber_encoded = False
1089 def ready(self): # pragma: no cover
1090 """Is object ready to be encoded?
1092 raise NotImplementedError()
1094 def _assert_ready(self):
1096 raise ObjNotReady(self.__class__.__name__)
1100 """Is either object or any elements inside is BER encoded?
1102 return self.expl_lenindef or self.lenindef or self.ber_encoded
1106 """Is object decoded?
1108 return (self.llen + self.vlen) > 0
1110 def copy(self): # pragma: no cover
1111 """Make a copy of object, safe to be mutated
1113 raise NotImplementedError()
1117 """See :ref:`decoding`
1119 return len(self.tag)
1123 """See :ref:`decoding`
1125 return self.tlen + self.llen + self.vlen
1127 def __str__(self): # pragma: no cover
1128 return self.__bytes__() if PY2 else self.__unicode__()
1130 def __ne__(self, their):
1131 return not(self == their)
1133 def __gt__(self, their): # pragma: no cover
1134 return not(self < their)
1136 def __le__(self, their): # pragma: no cover
1137 return (self == their) or (self < their)
1139 def __ge__(self, their): # pragma: no cover
1140 return (self == their) or (self > their)
1142 def _encode(self): # pragma: no cover
1143 raise NotImplementedError()
1145 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1146 raise NotImplementedError()
1149 """Encode the structure
1151 :returns: DER representation
1153 raw = self._encode()
1154 if self._expl is None:
1156 return b"".join((self._expl, len_encode(len(raw)), raw))
1166 _ctx_immutable=True,
1170 :param data: either binary or memoryview
1171 :param int offset: initial data's offset
1172 :param bool leavemm: do we need to leave memoryview of remaining
1173 data as is, or convert it to bytes otherwise
1174 :param ctx: optional :ref:`context <ctx>` governing decoding process
1175 :param tag_only: decode only the tag, without length and contents
1176 (used only in Choice and Set structures, trying to
1177 determine if tag satisfies the scheme)
1178 :param _ctx_immutable: do we need to copy ``ctx`` before using it
1179 :returns: (Obj, remaining data)
1181 .. seealso:: :ref:`decoding`
1185 elif _ctx_immutable:
1187 tlv = memoryview(data)
1188 if self._expl is None:
1189 result = self._decode(
1192 decode_path=decode_path,
1201 t, tlen, lv = tag_strip(tlv)
1202 except DecodeError as err:
1203 raise err.__class__(
1205 klass=self.__class__,
1206 decode_path=decode_path,
1211 klass=self.__class__,
1212 decode_path=decode_path,
1216 l, llen, v = len_decode(lv)
1217 except LenIndefForm as err:
1218 if not ctx.get("bered", False):
1219 raise err.__class__(
1221 klass=self.__class__,
1222 decode_path=decode_path,
1226 offset += tlen + llen
1227 result = self._decode(
1230 decode_path=decode_path,
1234 if tag_only: # pragma: no cover
1237 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1238 if eoc_expected.tobytes() != EOC:
1241 klass=self.__class__,
1242 decode_path=decode_path,
1246 obj.expl_lenindef = True
1247 except DecodeError as err:
1248 raise err.__class__(
1250 klass=self.__class__,
1251 decode_path=decode_path,
1256 raise NotEnoughData(
1257 "encoded length is longer than data",
1258 klass=self.__class__,
1259 decode_path=decode_path,
1262 result = self._decode(
1264 offset=offset + tlen + llen,
1265 decode_path=decode_path,
1269 if tag_only: # pragma: no cover
1272 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1274 "explicit tag out-of-bound, longer than data",
1275 klass=self.__class__,
1276 decode_path=decode_path,
1279 return obj, (tail if leavemm else tail.tobytes())
1281 def decod(self, data, offset=0, decode_path=(), ctx=None):
1282 """Decode the data, check that tail is empty
1284 :raises ExceedingData: if tail is not empty
1286 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1287 (decode without tail) that also checks that there is no
1290 obj, tail = self.decode(
1293 decode_path=decode_path,
1298 raise ExceedingData(len(tail))
1303 """See :ref:`decoding`
1305 return self._expl is not None
1309 """See :ref:`decoding`
1314 def expl_tlen(self):
1315 """See :ref:`decoding`
1317 return len(self._expl)
1320 def expl_llen(self):
1321 """See :ref:`decoding`
1323 if self.expl_lenindef:
1325 return len(len_encode(self.tlvlen))
1328 def expl_offset(self):
1329 """See :ref:`decoding`
1331 return self.offset - self.expl_tlen - self.expl_llen
1334 def expl_vlen(self):
1335 """See :ref:`decoding`
1340 def expl_tlvlen(self):
1341 """See :ref:`decoding`
1343 return self.expl_tlen + self.expl_llen + self.expl_vlen
1346 def fulloffset(self):
1347 """See :ref:`decoding`
1349 return self.expl_offset if self.expled else self.offset
1353 """See :ref:`decoding`
1355 return self.expl_tlvlen if self.expled else self.tlvlen
1357 def pps_lenindef(self, decode_path):
1358 if self.lenindef and not (
1359 getattr(self, "defined", None) is not None and
1360 self.defined[1].lenindef
1363 asn1_type_name="EOC",
1365 decode_path=decode_path,
1367 self.offset + self.tlvlen -
1368 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1376 if self.expl_lenindef:
1378 asn1_type_name="EOC",
1379 obj_name="EXPLICIT",
1380 decode_path=decode_path,
1381 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1390 class DecodePathDefBy(object):
1391 """DEFINED BY representation inside decode path
1393 __slots__ = ("defined_by",)
1395 def __init__(self, defined_by):
1396 self.defined_by = defined_by
1398 def __ne__(self, their):
1399 return not(self == their)
1401 def __eq__(self, their):
1402 if not isinstance(their, self.__class__):
1404 return self.defined_by == their.defined_by
1407 return "DEFINED BY " + str(self.defined_by)
1410 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1413 ########################################################################
1415 ########################################################################
1417 PP = namedtuple("PP", (
1445 asn1_type_name="unknown",
1462 expl_lenindef=False,
1493 def _colourize(what, colour, with_colours, attrs=("bold",)):
1494 return colored(what, colour, attrs=attrs) if with_colours else what
1497 def colonize_hex(hexed):
1498 """Separate hexadecimal string with colons
1500 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1509 with_decode_path=False,
1510 decode_path_len_decrease=0,
1517 " " if pp.expl_offset is None else
1518 ("-%d" % (pp.offset - pp.expl_offset))
1520 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1522 col = _colourize(col, "red", with_colours, ())
1523 col += _colourize("B", "red", with_colours) if pp.bered else " "
1525 col = "[%d,%d,%4d]%s" % (
1529 LENINDEF_PP_CHAR if pp.lenindef else " "
1531 col = _colourize(col, "green", with_colours, ())
1533 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1534 if decode_path_len > 0:
1535 cols.append(" ." * decode_path_len)
1536 ent = pp.decode_path[-1]
1537 if isinstance(ent, DecodePathDefBy):
1538 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1539 value = str(ent.defined_by)
1542 len(oid_maps) > 0 and
1543 ent.defined_by.asn1_type_name ==
1544 ObjectIdentifier.asn1_type_name
1546 for oid_map in oid_maps:
1547 oid_name = oid_map.get(value)
1548 if oid_name is not None:
1549 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1551 if oid_name is None:
1552 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1554 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1555 if pp.expl is not None:
1556 klass, _, num = pp.expl
1557 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1558 cols.append(_colourize(col, "blue", with_colours))
1559 if pp.impl is not None:
1560 klass, _, num = pp.impl
1561 col = "[%s%d]" % (TagClassReprs[klass], num)
1562 cols.append(_colourize(col, "blue", with_colours))
1563 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1564 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1566 cols.append(_colourize("BER", "red", with_colours))
1567 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1568 if pp.value is not None:
1570 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1572 len(oid_maps) > 0 and
1573 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1575 for oid_map in oid_maps:
1576 oid_name = oid_map.get(value)
1577 if oid_name is not None:
1578 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1580 if pp.asn1_type_name == Integer.asn1_type_name:
1581 hex_repr = hex(int(pp.obj._value))[2:].upper()
1582 if len(hex_repr) % 2 != 0:
1583 hex_repr = "0" + hex_repr
1584 cols.append(_colourize(
1585 "(%s)" % colonize_hex(hex_repr),
1590 if isinstance(pp.blob, binary_type):
1591 cols.append(hexenc(pp.blob))
1592 elif isinstance(pp.blob, tuple):
1593 cols.append(", ".join(pp.blob))
1595 cols.append(_colourize("OPTIONAL", "red", with_colours))
1597 cols.append(_colourize("DEFAULT", "red", with_colours))
1598 if with_decode_path:
1599 cols.append(_colourize(
1600 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1604 return " ".join(cols)
1607 def pp_console_blob(pp, decode_path_len_decrease=0):
1608 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1609 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1610 if decode_path_len > 0:
1611 cols.append(" ." * (decode_path_len + 1))
1612 if isinstance(pp.blob, binary_type):
1613 blob = hexenc(pp.blob).upper()
1614 for i in six_xrange(0, len(blob), 32):
1615 chunk = blob[i:i + 32]
1616 yield " ".join(cols + [colonize_hex(chunk)])
1617 elif isinstance(pp.blob, tuple):
1618 yield " ".join(cols + [", ".join(pp.blob)])
1626 with_decode_path=False,
1627 decode_path_only=(),
1629 """Pretty print object
1631 :param Obj obj: object you want to pretty print
1632 :param oid_maps: list of ``OID <-> humand readable string`` dictionary.
1633 When OID from it is met, then its humand readable form
1635 :param big_blobs: if large binary objects are met (like OctetString
1636 values), do we need to print them too, on separate
1638 :param with_colours: colourize output, if ``termcolor`` library
1640 :param with_decode_path: print decode path
1641 :param decode_path_only: print only that specified decode path
1643 def _pprint_pps(pps):
1645 if hasattr(pp, "_fields"):
1647 decode_path_only != () and
1649 str(p) for p in pp.decode_path[:len(decode_path_only)]
1650 ) != decode_path_only
1654 yield pp_console_row(
1659 with_colours=with_colours,
1660 with_decode_path=with_decode_path,
1661 decode_path_len_decrease=len(decode_path_only),
1663 for row in pp_console_blob(
1665 decode_path_len_decrease=len(decode_path_only),
1669 yield pp_console_row(
1674 with_colours=with_colours,
1675 with_decode_path=with_decode_path,
1676 decode_path_len_decrease=len(decode_path_only),
1679 for row in _pprint_pps(pp):
1681 return "\n".join(_pprint_pps(obj.pps()))
1684 ########################################################################
1685 # ASN.1 primitive types
1686 ########################################################################
1689 """``BOOLEAN`` boolean type
1691 >>> b = Boolean(True)
1693 >>> b == Boolean(True)
1699 tag_default = tag_encode(1)
1700 asn1_type_name = "BOOLEAN"
1712 :param value: set the value. Either boolean type, or
1713 :py:class:`pyderasn.Boolean` object
1714 :param bytes impl: override default tag with ``IMPLICIT`` one
1715 :param bytes expl: override default tag with ``EXPLICIT`` one
1716 :param default: set default value. Type same as in ``value``
1717 :param bool optional: is object ``OPTIONAL`` in sequence
1719 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1720 self._value = None if value is None else self._value_sanitize(value)
1721 if default is not None:
1722 default = self._value_sanitize(default)
1723 self.default = self.__class__(
1729 self._value = default
1731 def _value_sanitize(self, value):
1732 if isinstance(value, bool):
1734 if issubclass(value.__class__, Boolean):
1736 raise InvalidValueType((self.__class__, bool))
1740 return self._value is not None
1743 obj = self.__class__()
1744 obj._value = self._value
1746 obj._expl = self._expl
1747 obj.default = self.default
1748 obj.optional = self.optional
1749 obj.offset = self.offset
1750 obj.llen = self.llen
1751 obj.vlen = self.vlen
1752 obj.expl_lenindef = self.expl_lenindef
1753 obj.lenindef = self.lenindef
1754 obj.ber_encoded = self.ber_encoded
1757 def __nonzero__(self):
1758 self._assert_ready()
1762 self._assert_ready()
1765 def __eq__(self, their):
1766 if isinstance(their, bool):
1767 return self._value == their
1768 if not issubclass(their.__class__, Boolean):
1771 self._value == their._value and
1772 self.tag == their.tag and
1773 self._expl == their._expl
1784 return self.__class__(
1786 impl=self.tag if impl is None else impl,
1787 expl=self._expl if expl is None else expl,
1788 default=self.default if default is None else default,
1789 optional=self.optional if optional is None else optional,
1793 self._assert_ready()
1797 (b"\xFF" if self._value else b"\x00"),
1800 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1802 t, _, lv = tag_strip(tlv)
1803 except DecodeError as err:
1804 raise err.__class__(
1806 klass=self.__class__,
1807 decode_path=decode_path,
1812 klass=self.__class__,
1813 decode_path=decode_path,
1819 l, _, v = len_decode(lv)
1820 except DecodeError as err:
1821 raise err.__class__(
1823 klass=self.__class__,
1824 decode_path=decode_path,
1828 raise InvalidLength(
1829 "Boolean's length must be equal to 1",
1830 klass=self.__class__,
1831 decode_path=decode_path,
1835 raise NotEnoughData(
1836 "encoded length is longer than data",
1837 klass=self.__class__,
1838 decode_path=decode_path,
1841 first_octet = byte2int(v)
1843 if first_octet == 0:
1845 elif first_octet == 0xFF:
1847 elif ctx.get("bered", False):
1852 "unacceptable Boolean value",
1853 klass=self.__class__,
1854 decode_path=decode_path,
1857 obj = self.__class__(
1861 default=self.default,
1862 optional=self.optional,
1863 _decoded=(offset, 1, 1),
1865 obj.ber_encoded = ber_encoded
1869 return pp_console_row(next(self.pps()))
1871 def pps(self, decode_path=()):
1874 asn1_type_name=self.asn1_type_name,
1875 obj_name=self.__class__.__name__,
1876 decode_path=decode_path,
1877 value=str(self._value) if self.ready else None,
1878 optional=self.optional,
1879 default=self == self.default,
1880 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1881 expl=None if self._expl is None else tag_decode(self._expl),
1886 expl_offset=self.expl_offset if self.expled else None,
1887 expl_tlen=self.expl_tlen if self.expled else None,
1888 expl_llen=self.expl_llen if self.expled else None,
1889 expl_vlen=self.expl_vlen if self.expled else None,
1890 expl_lenindef=self.expl_lenindef,
1891 ber_encoded=self.ber_encoded,
1894 for pp in self.pps_lenindef(decode_path):
1899 """``INTEGER`` integer type
1901 >>> b = Integer(-123)
1903 >>> b == Integer(-123)
1908 >>> Integer(2, bounds=(1, 3))
1910 >>> Integer(5, bounds=(1, 3))
1911 Traceback (most recent call last):
1912 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1916 class Version(Integer):
1923 >>> v = Version("v1")
1930 {'v3': 2, 'v1': 0, 'v2': 1}
1932 __slots__ = ("specs", "_bound_min", "_bound_max")
1933 tag_default = tag_encode(2)
1934 asn1_type_name = "INTEGER"
1948 :param value: set the value. Either integer type, named value
1949 (if ``schema`` is specified in the class), or
1950 :py:class:`pyderasn.Integer` object
1951 :param bounds: set ``(MIN, MAX)`` value constraint.
1952 (-inf, +inf) by default
1953 :param bytes impl: override default tag with ``IMPLICIT`` one
1954 :param bytes expl: override default tag with ``EXPLICIT`` one
1955 :param default: set default value. Type same as in ``value``
1956 :param bool optional: is object ``OPTIONAL`` in sequence
1958 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
1960 specs = getattr(self, "schema", {}) if _specs is None else _specs
1961 self.specs = specs if isinstance(specs, dict) else dict(specs)
1962 self._bound_min, self._bound_max = getattr(
1965 (float("-inf"), float("+inf")),
1966 ) if bounds is None else bounds
1967 if value is not None:
1968 self._value = self._value_sanitize(value)
1969 if default is not None:
1970 default = self._value_sanitize(default)
1971 self.default = self.__class__(
1977 if self._value is None:
1978 self._value = default
1980 def _value_sanitize(self, value):
1981 if isinstance(value, integer_types):
1983 elif issubclass(value.__class__, Integer):
1984 value = value._value
1985 elif isinstance(value, str):
1986 value = self.specs.get(value)
1988 raise ObjUnknown("integer value: %s" % value)
1990 raise InvalidValueType((self.__class__, int, str))
1991 if not self._bound_min <= value <= self._bound_max:
1992 raise BoundsError(self._bound_min, value, self._bound_max)
1997 return self._value is not None
2000 obj = self.__class__(_specs=self.specs)
2001 obj._value = self._value
2002 obj._bound_min = self._bound_min
2003 obj._bound_max = self._bound_max
2005 obj._expl = self._expl
2006 obj.default = self.default
2007 obj.optional = self.optional
2008 obj.offset = self.offset
2009 obj.llen = self.llen
2010 obj.vlen = self.vlen
2011 obj.expl_lenindef = self.expl_lenindef
2012 obj.lenindef = self.lenindef
2013 obj.ber_encoded = self.ber_encoded
2017 self._assert_ready()
2018 return int(self._value)
2021 self._assert_ready()
2024 bytes(self._expl or b"") +
2025 str(self._value).encode("ascii"),
2028 def __eq__(self, their):
2029 if isinstance(their, integer_types):
2030 return self._value == their
2031 if not issubclass(their.__class__, Integer):
2034 self._value == their._value and
2035 self.tag == their.tag and
2036 self._expl == their._expl
2039 def __lt__(self, their):
2040 return self._value < their._value
2044 for name, value in iteritems(self.specs):
2045 if value == self._value:
2058 return self.__class__(
2061 (self._bound_min, self._bound_max)
2062 if bounds is None else bounds
2064 impl=self.tag if impl is None else impl,
2065 expl=self._expl if expl is None else expl,
2066 default=self.default if default is None else default,
2067 optional=self.optional if optional is None else optional,
2072 self._assert_ready()
2076 octets = bytearray([0])
2080 octets = bytearray()
2082 octets.append((value & 0xFF) ^ 0xFF)
2084 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2087 octets = bytearray()
2089 octets.append(value & 0xFF)
2091 if octets[-1] & 0x80 > 0:
2094 octets = bytes(octets)
2096 bytes_len = ceil(value.bit_length() / 8) or 1
2099 octets = value.to_bytes(
2104 except OverflowError:
2108 return b"".join((self.tag, len_encode(len(octets)), octets))
2110 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2112 t, _, lv = tag_strip(tlv)
2113 except DecodeError as err:
2114 raise err.__class__(
2116 klass=self.__class__,
2117 decode_path=decode_path,
2122 klass=self.__class__,
2123 decode_path=decode_path,
2129 l, llen, v = len_decode(lv)
2130 except DecodeError as err:
2131 raise err.__class__(
2133 klass=self.__class__,
2134 decode_path=decode_path,
2138 raise NotEnoughData(
2139 "encoded length is longer than data",
2140 klass=self.__class__,
2141 decode_path=decode_path,
2145 raise NotEnoughData(
2147 klass=self.__class__,
2148 decode_path=decode_path,
2151 v, tail = v[:l], v[l:]
2152 first_octet = byte2int(v)
2154 second_octet = byte2int(v[1:])
2156 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2157 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2160 "non normalized integer",
2161 klass=self.__class__,
2162 decode_path=decode_path,
2167 if first_octet & 0x80 > 0:
2168 octets = bytearray()
2169 for octet in bytearray(v):
2170 octets.append(octet ^ 0xFF)
2171 for octet in octets:
2172 value = (value << 8) | octet
2176 for octet in bytearray(v):
2177 value = (value << 8) | octet
2179 value = int.from_bytes(v, byteorder="big", signed=True)
2181 obj = self.__class__(
2183 bounds=(self._bound_min, self._bound_max),
2186 default=self.default,
2187 optional=self.optional,
2189 _decoded=(offset, llen, l),
2191 except BoundsError as err:
2194 klass=self.__class__,
2195 decode_path=decode_path,
2201 return pp_console_row(next(self.pps()))
2203 def pps(self, decode_path=()):
2206 asn1_type_name=self.asn1_type_name,
2207 obj_name=self.__class__.__name__,
2208 decode_path=decode_path,
2209 value=(self.named or str(self._value)) if self.ready else None,
2210 optional=self.optional,
2211 default=self == self.default,
2212 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2213 expl=None if self._expl is None else tag_decode(self._expl),
2218 expl_offset=self.expl_offset if self.expled else None,
2219 expl_tlen=self.expl_tlen if self.expled else None,
2220 expl_llen=self.expl_llen if self.expled else None,
2221 expl_vlen=self.expl_vlen if self.expled else None,
2222 expl_lenindef=self.expl_lenindef,
2225 for pp in self.pps_lenindef(decode_path):
2229 SET01 = frozenset(("0", "1"))
2232 class BitString(Obj):
2233 """``BIT STRING`` bit string type
2235 >>> BitString(b"hello world")
2236 BIT STRING 88 bits 68656c6c6f20776f726c64
2239 >>> b == b"hello world"
2244 >>> BitString("'0A3B5F291CD'H")
2245 BIT STRING 44 bits 0a3b5f291cd0
2246 >>> b = BitString("'010110000000'B")
2247 BIT STRING 12 bits 5800
2250 >>> b[0], b[1], b[2], b[3]
2251 (False, True, False, True)
2255 [False, True, False, True, True, False, False, False, False, False, False, False]
2259 class KeyUsage(BitString):
2261 ("digitalSignature", 0),
2262 ("nonRepudiation", 1),
2263 ("keyEncipherment", 2),
2266 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2267 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2269 ['nonRepudiation', 'keyEncipherment']
2271 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2275 Pay attention that BIT STRING can be encoded both in primitive
2276 and constructed forms. Decoder always checks constructed form tag
2277 additionally to specified primitive one. If BER decoding is
2278 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2279 of DER restrictions.
2281 __slots__ = ("tag_constructed", "specs", "defined")
2282 tag_default = tag_encode(3)
2283 asn1_type_name = "BIT STRING"
2296 :param value: set the value. Either binary type, tuple of named
2297 values (if ``schema`` is specified in the class),
2298 string in ``'XXX...'B`` form, or
2299 :py:class:`pyderasn.BitString` object
2300 :param bytes impl: override default tag with ``IMPLICIT`` one
2301 :param bytes expl: override default tag with ``EXPLICIT`` one
2302 :param default: set default value. Type same as in ``value``
2303 :param bool optional: is object ``OPTIONAL`` in sequence
2305 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2306 specs = getattr(self, "schema", {}) if _specs is None else _specs
2307 self.specs = specs if isinstance(specs, dict) else dict(specs)
2308 self._value = None if value is None else self._value_sanitize(value)
2309 if default is not None:
2310 default = self._value_sanitize(default)
2311 self.default = self.__class__(
2317 self._value = default
2319 tag_klass, _, tag_num = tag_decode(self.tag)
2320 self.tag_constructed = tag_encode(
2322 form=TagFormConstructed,
2326 def _bits2octets(self, bits):
2327 if len(self.specs) > 0:
2328 bits = bits.rstrip("0")
2330 bits += "0" * ((8 - (bit_len % 8)) % 8)
2331 octets = bytearray(len(bits) // 8)
2332 for i in six_xrange(len(octets)):
2333 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2334 return bit_len, bytes(octets)
2336 def _value_sanitize(self, value):
2337 if isinstance(value, (string_types, binary_type)):
2339 isinstance(value, string_types) and
2340 value.startswith("'")
2342 if value.endswith("'B"):
2344 if not frozenset(value) <= SET01:
2345 raise ValueError("B's coding contains unacceptable chars")
2346 return self._bits2octets(value)
2347 if value.endswith("'H"):
2351 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2353 if isinstance(value, binary_type):
2354 return (len(value) * 8, value)
2355 raise InvalidValueType((self.__class__, string_types, binary_type))
2356 if isinstance(value, tuple):
2359 isinstance(value[0], integer_types) and
2360 isinstance(value[1], binary_type)
2365 bit = self.specs.get(name)
2367 raise ObjUnknown("BitString value: %s" % name)
2370 return self._bits2octets("")
2371 bits = frozenset(bits)
2372 return self._bits2octets("".join(
2373 ("1" if bit in bits else "0")
2374 for bit in six_xrange(max(bits) + 1)
2376 if issubclass(value.__class__, BitString):
2378 raise InvalidValueType((self.__class__, binary_type, string_types))
2382 return self._value is not None
2385 obj = self.__class__(_specs=self.specs)
2387 if value is not None:
2388 value = (value[0], value[1])
2391 obj._expl = self._expl
2392 obj.default = self.default
2393 obj.optional = self.optional
2394 obj.offset = self.offset
2395 obj.llen = self.llen
2396 obj.vlen = self.vlen
2397 obj.expl_lenindef = self.expl_lenindef
2398 obj.lenindef = self.lenindef
2399 obj.ber_encoded = self.ber_encoded
2403 self._assert_ready()
2404 for i in six_xrange(self._value[0]):
2409 self._assert_ready()
2410 return self._value[0]
2412 def __bytes__(self):
2413 self._assert_ready()
2414 return self._value[1]
2416 def __eq__(self, their):
2417 if isinstance(their, bytes):
2418 return self._value[1] == their
2419 if not issubclass(their.__class__, BitString):
2422 self._value == their._value and
2423 self.tag == their.tag and
2424 self._expl == their._expl
2429 return [name for name, bit in iteritems(self.specs) if self[bit]]
2439 return self.__class__(
2441 impl=self.tag if impl is None else impl,
2442 expl=self._expl if expl is None else expl,
2443 default=self.default if default is None else default,
2444 optional=self.optional if optional is None else optional,
2448 def __getitem__(self, key):
2449 if isinstance(key, int):
2450 bit_len, octets = self._value
2454 byte2int(memoryview(octets)[key // 8:]) >>
2457 if isinstance(key, string_types):
2458 value = self.specs.get(key)
2460 raise ObjUnknown("BitString value: %s" % key)
2462 raise InvalidValueType((int, str))
2465 self._assert_ready()
2466 bit_len, octets = self._value
2469 len_encode(len(octets) + 1),
2470 int2byte((8 - bit_len % 8) % 8),
2474 def _decode_chunk(self, lv, offset, decode_path):
2476 l, llen, v = len_decode(lv)
2477 except DecodeError as err:
2478 raise err.__class__(
2480 klass=self.__class__,
2481 decode_path=decode_path,
2485 raise NotEnoughData(
2486 "encoded length is longer than data",
2487 klass=self.__class__,
2488 decode_path=decode_path,
2492 raise NotEnoughData(
2494 klass=self.__class__,
2495 decode_path=decode_path,
2498 pad_size = byte2int(v)
2499 if l == 1 and pad_size != 0:
2501 "invalid empty value",
2502 klass=self.__class__,
2503 decode_path=decode_path,
2509 klass=self.__class__,
2510 decode_path=decode_path,
2513 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2516 klass=self.__class__,
2517 decode_path=decode_path,
2520 v, tail = v[:l], v[l:]
2521 obj = self.__class__(
2522 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2525 default=self.default,
2526 optional=self.optional,
2528 _decoded=(offset, llen, l),
2532 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2534 t, tlen, lv = tag_strip(tlv)
2535 except DecodeError as err:
2536 raise err.__class__(
2538 klass=self.__class__,
2539 decode_path=decode_path,
2543 if tag_only: # pragma: no cover
2545 return self._decode_chunk(lv, offset, decode_path)
2546 if t == self.tag_constructed:
2547 if not ctx.get("bered", False):
2549 "unallowed BER constructed encoding",
2550 klass=self.__class__,
2551 decode_path=decode_path,
2554 if tag_only: # pragma: no cover
2558 l, llen, v = len_decode(lv)
2559 except LenIndefForm:
2560 llen, l, v = 1, 0, lv[1:]
2562 except DecodeError as err:
2563 raise err.__class__(
2565 klass=self.__class__,
2566 decode_path=decode_path,
2570 raise NotEnoughData(
2571 "encoded length is longer than data",
2572 klass=self.__class__,
2573 decode_path=decode_path,
2576 if not lenindef and l == 0:
2577 raise NotEnoughData(
2579 klass=self.__class__,
2580 decode_path=decode_path,
2584 sub_offset = offset + tlen + llen
2588 if v[:EOC_LEN].tobytes() == EOC:
2595 "chunk out of bounds",
2596 klass=self.__class__,
2597 decode_path=decode_path + (str(len(chunks) - 1),),
2598 offset=chunks[-1].offset,
2600 sub_decode_path = decode_path + (str(len(chunks)),)
2602 chunk, v_tail = BitString().decode(
2605 decode_path=sub_decode_path,
2608 _ctx_immutable=False,
2612 "expected BitString encoded chunk",
2613 klass=self.__class__,
2614 decode_path=sub_decode_path,
2617 chunks.append(chunk)
2618 sub_offset += chunk.tlvlen
2619 vlen += chunk.tlvlen
2621 if len(chunks) == 0:
2624 klass=self.__class__,
2625 decode_path=decode_path,
2630 for chunk_i, chunk in enumerate(chunks[:-1]):
2631 if chunk.bit_len % 8 != 0:
2633 "BitString chunk is not multiple of 8 bits",
2634 klass=self.__class__,
2635 decode_path=decode_path + (str(chunk_i),),
2636 offset=chunk.offset,
2638 values.append(bytes(chunk))
2639 bit_len += chunk.bit_len
2640 chunk_last = chunks[-1]
2641 values.append(bytes(chunk_last))
2642 bit_len += chunk_last.bit_len
2643 obj = self.__class__(
2644 value=(bit_len, b"".join(values)),
2647 default=self.default,
2648 optional=self.optional,
2650 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2652 obj.lenindef = lenindef
2653 obj.ber_encoded = True
2654 return obj, (v[EOC_LEN:] if lenindef else v)
2656 klass=self.__class__,
2657 decode_path=decode_path,
2662 return pp_console_row(next(self.pps()))
2664 def pps(self, decode_path=()):
2668 bit_len, blob = self._value
2669 value = "%d bits" % bit_len
2670 if len(self.specs) > 0:
2671 blob = tuple(self.named)
2674 asn1_type_name=self.asn1_type_name,
2675 obj_name=self.__class__.__name__,
2676 decode_path=decode_path,
2679 optional=self.optional,
2680 default=self == self.default,
2681 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2682 expl=None if self._expl is None else tag_decode(self._expl),
2687 expl_offset=self.expl_offset if self.expled else None,
2688 expl_tlen=self.expl_tlen if self.expled else None,
2689 expl_llen=self.expl_llen if self.expled else None,
2690 expl_vlen=self.expl_vlen if self.expled else None,
2691 expl_lenindef=self.expl_lenindef,
2692 lenindef=self.lenindef,
2693 ber_encoded=self.ber_encoded,
2696 defined_by, defined = self.defined or (None, None)
2697 if defined_by is not None:
2699 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2701 for pp in self.pps_lenindef(decode_path):
2705 class OctetString(Obj):
2706 """``OCTET STRING`` binary string type
2708 >>> s = OctetString(b"hello world")
2709 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2710 >>> s == OctetString(b"hello world")
2715 >>> OctetString(b"hello", bounds=(4, 4))
2716 Traceback (most recent call last):
2717 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2718 >>> OctetString(b"hell", bounds=(4, 4))
2719 OCTET STRING 4 bytes 68656c6c
2723 Pay attention that OCTET STRING can be encoded both in primitive
2724 and constructed forms. Decoder always checks constructed form tag
2725 additionally to specified primitive one. If BER decoding is
2726 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2727 of DER restrictions.
2729 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2730 tag_default = tag_encode(4)
2731 asn1_type_name = "OCTET STRING"
2744 :param value: set the value. Either binary type, or
2745 :py:class:`pyderasn.OctetString` object
2746 :param bounds: set ``(MIN, MAX)`` value size constraint.
2747 (-inf, +inf) by default
2748 :param bytes impl: override default tag with ``IMPLICIT`` one
2749 :param bytes expl: override default tag with ``EXPLICIT`` one
2750 :param default: set default value. Type same as in ``value``
2751 :param bool optional: is object ``OPTIONAL`` in sequence
2753 super(OctetString, self).__init__(
2761 self._bound_min, self._bound_max = getattr(
2765 ) if bounds is None else bounds
2766 if value is not None:
2767 self._value = self._value_sanitize(value)
2768 if default is not None:
2769 default = self._value_sanitize(default)
2770 self.default = self.__class__(
2775 if self._value is None:
2776 self._value = default
2778 tag_klass, _, tag_num = tag_decode(self.tag)
2779 self.tag_constructed = tag_encode(
2781 form=TagFormConstructed,
2785 def _value_sanitize(self, value):
2786 if isinstance(value, binary_type):
2788 elif issubclass(value.__class__, OctetString):
2789 value = value._value
2791 raise InvalidValueType((self.__class__, bytes))
2792 if not self._bound_min <= len(value) <= self._bound_max:
2793 raise BoundsError(self._bound_min, len(value), self._bound_max)
2798 return self._value is not None
2801 obj = self.__class__()
2802 obj._value = self._value
2803 obj._bound_min = self._bound_min
2804 obj._bound_max = self._bound_max
2806 obj._expl = self._expl
2807 obj.default = self.default
2808 obj.optional = self.optional
2809 obj.offset = self.offset
2810 obj.llen = self.llen
2811 obj.vlen = self.vlen
2812 obj.expl_lenindef = self.expl_lenindef
2813 obj.lenindef = self.lenindef
2814 obj.ber_encoded = self.ber_encoded
2817 def __bytes__(self):
2818 self._assert_ready()
2821 def __eq__(self, their):
2822 if isinstance(their, binary_type):
2823 return self._value == their
2824 if not issubclass(their.__class__, OctetString):
2827 self._value == their._value and
2828 self.tag == their.tag and
2829 self._expl == their._expl
2832 def __lt__(self, their):
2833 return self._value < their._value
2844 return self.__class__(
2847 (self._bound_min, self._bound_max)
2848 if bounds is None else bounds
2850 impl=self.tag if impl is None else impl,
2851 expl=self._expl if expl is None else expl,
2852 default=self.default if default is None else default,
2853 optional=self.optional if optional is None else optional,
2857 self._assert_ready()
2860 len_encode(len(self._value)),
2864 def _decode_chunk(self, lv, offset, decode_path):
2866 l, llen, v = len_decode(lv)
2867 except DecodeError as err:
2868 raise err.__class__(
2870 klass=self.__class__,
2871 decode_path=decode_path,
2875 raise NotEnoughData(
2876 "encoded length is longer than data",
2877 klass=self.__class__,
2878 decode_path=decode_path,
2881 v, tail = v[:l], v[l:]
2883 obj = self.__class__(
2885 bounds=(self._bound_min, self._bound_max),
2888 default=self.default,
2889 optional=self.optional,
2890 _decoded=(offset, llen, l),
2892 except DecodeError as err:
2895 klass=self.__class__,
2896 decode_path=decode_path,
2899 except BoundsError as err:
2902 klass=self.__class__,
2903 decode_path=decode_path,
2908 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2910 t, tlen, lv = tag_strip(tlv)
2911 except DecodeError as err:
2912 raise err.__class__(
2914 klass=self.__class__,
2915 decode_path=decode_path,
2921 return self._decode_chunk(lv, offset, decode_path)
2922 if t == self.tag_constructed:
2923 if not ctx.get("bered", False):
2925 "unallowed BER constructed encoding",
2926 klass=self.__class__,
2927 decode_path=decode_path,
2934 l, llen, v = len_decode(lv)
2935 except LenIndefForm:
2936 llen, l, v = 1, 0, lv[1:]
2938 except DecodeError as err:
2939 raise err.__class__(
2941 klass=self.__class__,
2942 decode_path=decode_path,
2946 raise NotEnoughData(
2947 "encoded length is longer than data",
2948 klass=self.__class__,
2949 decode_path=decode_path,
2953 sub_offset = offset + tlen + llen
2957 if v[:EOC_LEN].tobytes() == EOC:
2964 "chunk out of bounds",
2965 klass=self.__class__,
2966 decode_path=decode_path + (str(len(chunks) - 1),),
2967 offset=chunks[-1].offset,
2969 sub_decode_path = decode_path + (str(len(chunks)),)
2971 chunk, v_tail = OctetString().decode(
2974 decode_path=sub_decode_path,
2977 _ctx_immutable=False,
2981 "expected OctetString encoded chunk",
2982 klass=self.__class__,
2983 decode_path=sub_decode_path,
2986 chunks.append(chunk)
2987 sub_offset += chunk.tlvlen
2988 vlen += chunk.tlvlen
2991 obj = self.__class__(
2992 value=b"".join(bytes(chunk) for chunk in chunks),
2993 bounds=(self._bound_min, self._bound_max),
2996 default=self.default,
2997 optional=self.optional,
2998 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3000 except DecodeError as err:
3003 klass=self.__class__,
3004 decode_path=decode_path,
3007 except BoundsError as err:
3010 klass=self.__class__,
3011 decode_path=decode_path,
3014 obj.lenindef = lenindef
3015 obj.ber_encoded = True
3016 return obj, (v[EOC_LEN:] if lenindef else v)
3018 klass=self.__class__,
3019 decode_path=decode_path,
3024 return pp_console_row(next(self.pps()))
3026 def pps(self, decode_path=()):
3029 asn1_type_name=self.asn1_type_name,
3030 obj_name=self.__class__.__name__,
3031 decode_path=decode_path,
3032 value=("%d bytes" % len(self._value)) if self.ready else None,
3033 blob=self._value if self.ready else None,
3034 optional=self.optional,
3035 default=self == self.default,
3036 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3037 expl=None if self._expl is None else tag_decode(self._expl),
3042 expl_offset=self.expl_offset if self.expled else None,
3043 expl_tlen=self.expl_tlen if self.expled else None,
3044 expl_llen=self.expl_llen if self.expled else None,
3045 expl_vlen=self.expl_vlen if self.expled else None,
3046 expl_lenindef=self.expl_lenindef,
3047 lenindef=self.lenindef,
3048 ber_encoded=self.ber_encoded,
3051 defined_by, defined = self.defined or (None, None)
3052 if defined_by is not None:
3054 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3056 for pp in self.pps_lenindef(decode_path):
3061 """``NULL`` null object
3069 tag_default = tag_encode(5)
3070 asn1_type_name = "NULL"
3074 value=None, # unused, but Sequence passes it
3081 :param bytes impl: override default tag with ``IMPLICIT`` one
3082 :param bytes expl: override default tag with ``EXPLICIT`` one
3083 :param bool optional: is object ``OPTIONAL`` in sequence
3085 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3093 obj = self.__class__()
3095 obj._expl = self._expl
3096 obj.default = self.default
3097 obj.optional = self.optional
3098 obj.offset = self.offset
3099 obj.llen = self.llen
3100 obj.vlen = self.vlen
3101 obj.expl_lenindef = self.expl_lenindef
3102 obj.lenindef = self.lenindef
3103 obj.ber_encoded = self.ber_encoded
3106 def __eq__(self, their):
3107 if not issubclass(their.__class__, Null):
3110 self.tag == their.tag and
3111 self._expl == their._expl
3121 return self.__class__(
3122 impl=self.tag if impl is None else impl,
3123 expl=self._expl if expl is None else expl,
3124 optional=self.optional if optional is None else optional,
3128 return self.tag + len_encode(0)
3130 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3132 t, _, lv = tag_strip(tlv)
3133 except DecodeError as err:
3134 raise err.__class__(
3136 klass=self.__class__,
3137 decode_path=decode_path,
3142 klass=self.__class__,
3143 decode_path=decode_path,
3146 if tag_only: # pragma: no cover
3149 l, _, v = len_decode(lv)
3150 except DecodeError as err:
3151 raise err.__class__(
3153 klass=self.__class__,
3154 decode_path=decode_path,
3158 raise InvalidLength(
3159 "Null must have zero length",
3160 klass=self.__class__,
3161 decode_path=decode_path,
3164 obj = self.__class__(
3167 optional=self.optional,
3168 _decoded=(offset, 1, 0),
3173 return pp_console_row(next(self.pps()))
3175 def pps(self, decode_path=()):
3178 asn1_type_name=self.asn1_type_name,
3179 obj_name=self.__class__.__name__,
3180 decode_path=decode_path,
3181 optional=self.optional,
3182 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3183 expl=None if self._expl is None else tag_decode(self._expl),
3188 expl_offset=self.expl_offset if self.expled else None,
3189 expl_tlen=self.expl_tlen if self.expled else None,
3190 expl_llen=self.expl_llen if self.expled else None,
3191 expl_vlen=self.expl_vlen if self.expled else None,
3192 expl_lenindef=self.expl_lenindef,
3195 for pp in self.pps_lenindef(decode_path):
3199 class ObjectIdentifier(Obj):
3200 """``OBJECT IDENTIFIER`` OID type
3202 >>> oid = ObjectIdentifier((1, 2, 3))
3203 OBJECT IDENTIFIER 1.2.3
3204 >>> oid == ObjectIdentifier("1.2.3")
3210 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3211 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3213 >>> str(ObjectIdentifier((3, 1)))
3214 Traceback (most recent call last):
3215 pyderasn.InvalidOID: unacceptable first arc value
3217 __slots__ = ("defines",)
3218 tag_default = tag_encode(6)
3219 asn1_type_name = "OBJECT IDENTIFIER"
3232 :param value: set the value. Either tuples of integers,
3233 string of "."-concatenated integers, or
3234 :py:class:`pyderasn.ObjectIdentifier` object
3235 :param defines: sequence of tuples. Each tuple has two elements.
3236 First one is relative to current one decode
3237 path, aiming to the field defined by that OID.
3238 Read about relative path in
3239 :py:func:`pyderasn.abs_decode_path`. Second
3240 tuple element is ``{OID: pyderasn.Obj()}``
3241 dictionary, mapping between current OID value
3242 and structure applied to defined field.
3243 :ref:`Read about DEFINED BY <definedby>`
3244 :param bytes impl: override default tag with ``IMPLICIT`` one
3245 :param bytes expl: override default tag with ``EXPLICIT`` one
3246 :param default: set default value. Type same as in ``value``
3247 :param bool optional: is object ``OPTIONAL`` in sequence
3249 super(ObjectIdentifier, self).__init__(
3257 if value is not None:
3258 self._value = self._value_sanitize(value)
3259 if default is not None:
3260 default = self._value_sanitize(default)
3261 self.default = self.__class__(
3266 if self._value is None:
3267 self._value = default
3268 self.defines = defines
3270 def __add__(self, their):
3271 if isinstance(their, self.__class__):
3272 return self.__class__(self._value + their._value)
3273 if isinstance(their, tuple):
3274 return self.__class__(self._value + their)
3275 raise InvalidValueType((self.__class__, tuple))
3277 def _value_sanitize(self, value):
3278 if issubclass(value.__class__, ObjectIdentifier):
3280 if isinstance(value, string_types):
3282 value = tuple(int(arc) for arc in value.split("."))
3284 raise InvalidOID("unacceptable arcs values")
3285 if isinstance(value, tuple):
3287 raise InvalidOID("less than 2 arcs")
3288 first_arc = value[0]
3289 if first_arc in (0, 1):
3290 if not (0 <= value[1] <= 39):
3291 raise InvalidOID("second arc is too wide")
3292 elif first_arc == 2:
3295 raise InvalidOID("unacceptable first arc value")
3297 raise InvalidValueType((self.__class__, str, tuple))
3301 return self._value is not None
3304 obj = self.__class__()
3305 obj._value = self._value
3306 obj.defines = self.defines
3308 obj._expl = self._expl
3309 obj.default = self.default
3310 obj.optional = self.optional
3311 obj.offset = self.offset
3312 obj.llen = self.llen
3313 obj.vlen = self.vlen
3314 obj.expl_lenindef = self.expl_lenindef
3315 obj.lenindef = self.lenindef
3316 obj.ber_encoded = self.ber_encoded
3320 self._assert_ready()
3321 return iter(self._value)
3324 return ".".join(str(arc) for arc in self._value or ())
3327 self._assert_ready()
3330 bytes(self._expl or b"") +
3331 str(self._value).encode("ascii"),
3334 def __eq__(self, their):
3335 if isinstance(their, tuple):
3336 return self._value == their
3337 if not issubclass(their.__class__, ObjectIdentifier):
3340 self.tag == their.tag and
3341 self._expl == their._expl and
3342 self._value == their._value
3345 def __lt__(self, their):
3346 return self._value < their._value
3357 return self.__class__(
3359 defines=self.defines if defines is None else defines,
3360 impl=self.tag if impl is None else impl,
3361 expl=self._expl if expl is None else expl,
3362 default=self.default if default is None else default,
3363 optional=self.optional if optional is None else optional,
3367 self._assert_ready()
3369 first_value = value[1]
3370 first_arc = value[0]
3373 elif first_arc == 1:
3375 elif first_arc == 2:
3377 else: # pragma: no cover
3378 raise RuntimeError("invalid arc is stored")
3379 octets = [zero_ended_encode(first_value)]
3380 for arc in value[2:]:
3381 octets.append(zero_ended_encode(arc))
3382 v = b"".join(octets)
3383 return b"".join((self.tag, len_encode(len(v)), v))
3385 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3387 t, _, lv = tag_strip(tlv)
3388 except DecodeError as err:
3389 raise err.__class__(
3391 klass=self.__class__,
3392 decode_path=decode_path,
3397 klass=self.__class__,
3398 decode_path=decode_path,
3401 if tag_only: # pragma: no cover
3404 l, llen, v = len_decode(lv)
3405 except DecodeError as err:
3406 raise err.__class__(
3408 klass=self.__class__,
3409 decode_path=decode_path,
3413 raise NotEnoughData(
3414 "encoded length is longer than data",
3415 klass=self.__class__,
3416 decode_path=decode_path,
3420 raise NotEnoughData(
3422 klass=self.__class__,
3423 decode_path=decode_path,
3426 v, tail = v[:l], v[l:]
3433 octet = indexbytes(v, i)
3434 if i == 0 and octet == 0x80:
3435 if ctx.get("bered", False):
3438 raise DecodeError("non normalized arc encoding")
3439 arc = (arc << 7) | (octet & 0x7F)
3440 if octet & 0x80 == 0:
3448 klass=self.__class__,
3449 decode_path=decode_path,
3453 second_arc = arcs[0]
3454 if 0 <= second_arc <= 39:
3456 elif 40 <= second_arc <= 79:
3462 obj = self.__class__(
3463 value=tuple([first_arc, second_arc] + arcs[1:]),
3466 default=self.default,
3467 optional=self.optional,
3468 _decoded=(offset, llen, l),
3471 obj.ber_encoded = True
3475 return pp_console_row(next(self.pps()))
3477 def pps(self, decode_path=()):
3480 asn1_type_name=self.asn1_type_name,
3481 obj_name=self.__class__.__name__,
3482 decode_path=decode_path,
3483 value=str(self) if self.ready else None,
3484 optional=self.optional,
3485 default=self == self.default,
3486 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3487 expl=None if self._expl is None else tag_decode(self._expl),
3492 expl_offset=self.expl_offset if self.expled else None,
3493 expl_tlen=self.expl_tlen if self.expled else None,
3494 expl_llen=self.expl_llen if self.expled else None,
3495 expl_vlen=self.expl_vlen if self.expled else None,
3496 expl_lenindef=self.expl_lenindef,
3497 ber_encoded=self.ber_encoded,
3500 for pp in self.pps_lenindef(decode_path):
3504 class Enumerated(Integer):
3505 """``ENUMERATED`` integer type
3507 This type is identical to :py:class:`pyderasn.Integer`, but requires
3508 schema to be specified and does not accept values missing from it.
3511 tag_default = tag_encode(10)
3512 asn1_type_name = "ENUMERATED"
3523 bounds=None, # dummy argument, workability for Integer.decode
3525 super(Enumerated, self).__init__(
3534 if len(self.specs) == 0:
3535 raise ValueError("schema must be specified")
3537 def _value_sanitize(self, value):
3538 if isinstance(value, self.__class__):
3539 value = value._value
3540 elif isinstance(value, integer_types):
3541 for _value in itervalues(self.specs):
3546 "unknown integer value: %s" % value,
3547 klass=self.__class__,
3549 elif isinstance(value, string_types):
3550 value = self.specs.get(value)
3552 raise ObjUnknown("integer value: %s" % value)
3554 raise InvalidValueType((self.__class__, int, str))
3558 obj = self.__class__(_specs=self.specs)
3559 obj._value = self._value
3560 obj._bound_min = self._bound_min
3561 obj._bound_max = self._bound_max
3563 obj._expl = self._expl
3564 obj.default = self.default
3565 obj.optional = self.optional
3566 obj.offset = self.offset
3567 obj.llen = self.llen
3568 obj.vlen = self.vlen
3569 obj.expl_lenindef = self.expl_lenindef
3570 obj.lenindef = self.lenindef
3571 obj.ber_encoded = self.ber_encoded
3583 return self.__class__(
3585 impl=self.tag if impl is None else impl,
3586 expl=self._expl if expl is None else expl,
3587 default=self.default if default is None else default,
3588 optional=self.optional if optional is None else optional,
3593 class CommonString(OctetString):
3594 """Common class for all strings
3596 Everything resembles :py:class:`pyderasn.OctetString`, except
3597 ability to deal with unicode text strings.
3599 >>> hexenc("привет мир".encode("utf-8"))
3600 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3601 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3603 >>> s = UTF8String("привет мир")
3604 UTF8String UTF8String привет мир
3606 'привет мир'
3607 >>> hexenc(bytes(s))
3608 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3610 >>> PrintableString("привет мир")
3611 Traceback (most recent call last):
3612 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3614 >>> BMPString("ада", bounds=(2, 2))
3615 Traceback (most recent call last):
3616 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3617 >>> s = BMPString("ад", bounds=(2, 2))
3620 >>> hexenc(bytes(s))
3628 * - :py:class:`pyderasn.UTF8String`
3630 * - :py:class:`pyderasn.NumericString`
3632 * - :py:class:`pyderasn.PrintableString`
3634 * - :py:class:`pyderasn.TeletexString`
3636 * - :py:class:`pyderasn.T61String`
3638 * - :py:class:`pyderasn.VideotexString`
3640 * - :py:class:`pyderasn.IA5String`
3642 * - :py:class:`pyderasn.GraphicString`
3644 * - :py:class:`pyderasn.VisibleString`
3646 * - :py:class:`pyderasn.ISO646String`
3648 * - :py:class:`pyderasn.GeneralString`
3650 * - :py:class:`pyderasn.UniversalString`
3652 * - :py:class:`pyderasn.BMPString`
3655 __slots__ = ("encoding",)
3657 def _value_sanitize(self, value):
3659 value_decoded = None
3660 if isinstance(value, self.__class__):
3661 value_raw = value._value
3662 elif isinstance(value, text_type):
3663 value_decoded = value
3664 elif isinstance(value, binary_type):
3667 raise InvalidValueType((self.__class__, text_type, binary_type))
3670 value_decoded.encode(self.encoding)
3671 if value_raw is None else value_raw
3674 value_raw.decode(self.encoding)
3675 if value_decoded is None else value_decoded
3677 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3678 raise DecodeError(str(err))
3679 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3687 def __eq__(self, their):
3688 if isinstance(their, binary_type):
3689 return self._value == their
3690 if isinstance(their, text_type):
3691 return self._value == their.encode(self.encoding)
3692 if not isinstance(their, self.__class__):
3695 self._value == their._value and
3696 self.tag == their.tag and
3697 self._expl == their._expl
3700 def __unicode__(self):
3702 return self._value.decode(self.encoding)
3703 return text_type(self._value)
3706 return pp_console_row(next(self.pps(no_unicode=PY2)))
3708 def pps(self, decode_path=(), no_unicode=False):
3711 value = hexenc(bytes(self)) if no_unicode else self.__unicode__()
3714 asn1_type_name=self.asn1_type_name,
3715 obj_name=self.__class__.__name__,
3716 decode_path=decode_path,
3718 optional=self.optional,
3719 default=self == self.default,
3720 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3721 expl=None if self._expl is None else tag_decode(self._expl),
3726 expl_offset=self.expl_offset if self.expled else None,
3727 expl_tlen=self.expl_tlen if self.expled else None,
3728 expl_llen=self.expl_llen if self.expled else None,
3729 expl_vlen=self.expl_vlen if self.expled else None,
3730 expl_lenindef=self.expl_lenindef,
3731 ber_encoded=self.ber_encoded,
3734 for pp in self.pps_lenindef(decode_path):
3738 class UTF8String(CommonString):
3740 tag_default = tag_encode(12)
3742 asn1_type_name = "UTF8String"
3745 class AllowableCharsMixin(object):
3747 def allowable_chars(self):
3749 return self._allowable_chars
3750 return frozenset(six_unichr(c) for c in self._allowable_chars)
3753 class NumericString(AllowableCharsMixin, CommonString):
3756 Its value is properly sanitized: only ASCII digits with spaces can
3759 >>> NumericString().allowable_chars
3760 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3763 tag_default = tag_encode(18)
3765 asn1_type_name = "NumericString"
3766 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3768 def _value_sanitize(self, value):
3769 value = super(NumericString, self)._value_sanitize(value)
3770 if not frozenset(value) <= self._allowable_chars:
3771 raise DecodeError("non-numeric value")
3775 class PrintableString(AllowableCharsMixin, CommonString):
3778 Its value is properly sanitized: see X.680 41.4 table 10.
3780 >>> PrintableString().allowable_chars
3781 frozenset([' ', "'", ..., 'z'])
3784 tag_default = tag_encode(19)
3786 asn1_type_name = "PrintableString"
3787 _allowable_chars = frozenset(
3788 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
3791 def _value_sanitize(self, value):
3792 value = super(PrintableString, self)._value_sanitize(value)
3793 if not frozenset(value) <= self._allowable_chars:
3794 raise DecodeError("non-printable value")
3798 class TeletexString(CommonString):
3800 tag_default = tag_encode(20)
3802 asn1_type_name = "TeletexString"
3805 class T61String(TeletexString):
3807 asn1_type_name = "T61String"
3810 class VideotexString(CommonString):
3812 tag_default = tag_encode(21)
3813 encoding = "iso-8859-1"
3814 asn1_type_name = "VideotexString"
3817 class IA5String(CommonString):
3819 tag_default = tag_encode(22)
3821 asn1_type_name = "IA5"
3824 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
3825 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
3826 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
3829 class UTCTime(CommonString):
3830 """``UTCTime`` datetime type
3832 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3833 UTCTime UTCTime 2017-09-30T22:07:50
3839 datetime.datetime(2017, 9, 30, 22, 7, 50)
3840 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
3841 datetime.datetime(1957, 9, 30, 22, 7, 50)
3845 BER encoding is unsupported.
3848 tag_default = tag_encode(23)
3850 asn1_type_name = "UTCTime"
3860 bounds=None, # dummy argument, workability for OctetString.decode
3863 :param value: set the value. Either datetime type, or
3864 :py:class:`pyderasn.UTCTime` object
3865 :param bytes impl: override default tag with ``IMPLICIT`` one
3866 :param bytes expl: override default tag with ``EXPLICIT`` one
3867 :param default: set default value. Type same as in ``value``
3868 :param bool optional: is object ``OPTIONAL`` in sequence
3870 super(UTCTime, self).__init__(
3878 if value is not None:
3879 self._value = self._value_sanitize(value)
3880 if default is not None:
3881 default = self._value_sanitize(default)
3882 self.default = self.__class__(
3887 if self._value is None:
3888 self._value = default
3890 def _strptime(self, value):
3891 # datetime.strptime's format: %y%m%d%H%M%SZ
3892 if len(value) != LEN_YYMMDDHHMMSSZ:
3893 raise ValueError("invalid UTCTime length")
3894 if value[-1] != "Z":
3895 raise ValueError("non UTC timezone")
3897 2000 + int(value[:2]), # %y
3898 int(value[2:4]), # %m
3899 int(value[4:6]), # %d
3900 int(value[6:8]), # %H
3901 int(value[8:10]), # %M
3902 int(value[10:12]), # %S
3905 def _value_sanitize(self, value):
3906 if isinstance(value, binary_type):
3908 value_decoded = value.decode("ascii")
3909 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3910 raise DecodeError("invalid UTCTime encoding: %r" % err)
3912 self._strptime(value_decoded)
3913 except (TypeError, ValueError) as err:
3914 raise DecodeError("invalid UTCTime format: %r" % err)
3916 if isinstance(value, self.__class__):
3918 if isinstance(value, datetime):
3919 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
3920 raise InvalidValueType((self.__class__, datetime))
3922 def __eq__(self, their):
3923 if isinstance(their, binary_type):
3924 return self._value == their
3925 if isinstance(their, datetime):
3926 return self.todatetime() == their
3927 if not isinstance(their, self.__class__):
3930 self._value == their._value and
3931 self.tag == their.tag and
3932 self._expl == their._expl
3935 def todatetime(self):
3936 """Convert to datetime
3940 Pay attention that UTCTime can not hold full year, so all years
3941 having < 50 years are treated as 20xx, 19xx otherwise, according
3942 to X.509 recomendation.
3944 value = self._strptime(self._value.decode("ascii"))
3945 year = value.year % 100
3947 year=(2000 + year) if year < 50 else (1900 + year),
3951 minute=value.minute,
3952 second=value.second,
3956 return pp_console_row(next(self.pps()))
3958 def pps(self, decode_path=()):
3961 asn1_type_name=self.asn1_type_name,
3962 obj_name=self.__class__.__name__,
3963 decode_path=decode_path,
3964 value=self.todatetime().isoformat() if self.ready else None,
3965 optional=self.optional,
3966 default=self == self.default,
3967 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3968 expl=None if self._expl is None else tag_decode(self._expl),
3973 expl_offset=self.expl_offset if self.expled else None,
3974 expl_tlen=self.expl_tlen if self.expled else None,
3975 expl_llen=self.expl_llen if self.expled else None,
3976 expl_vlen=self.expl_vlen if self.expled else None,
3977 expl_lenindef=self.expl_lenindef,
3978 ber_encoded=self.ber_encoded,
3981 for pp in self.pps_lenindef(decode_path):
3985 class GeneralizedTime(UTCTime):
3986 """``GeneralizedTime`` datetime type
3988 This type is similar to :py:class:`pyderasn.UTCTime`.
3990 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3991 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
3993 '20170930220750.000123Z'
3994 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
3995 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
3999 BER encoding is unsupported.
4003 Only microsecond fractions are supported.
4004 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4005 higher precision values.
4008 tag_default = tag_encode(24)
4009 asn1_type_name = "GeneralizedTime"
4011 def _strptime(self, value):
4013 if l == LEN_YYYYMMDDHHMMSSZ:
4014 # datetime.strptime's format: %y%m%d%H%M%SZ
4015 if value[-1] != "Z":
4016 raise ValueError("non UTC timezone")
4018 int(value[:4]), # %Y
4019 int(value[4:6]), # %m
4020 int(value[6:8]), # %d
4021 int(value[8:10]), # %H
4022 int(value[10:12]), # %M
4023 int(value[12:14]), # %S
4025 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4026 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4027 if value[-1] != "Z":
4028 raise ValueError("non UTC timezone")
4029 if value[14] != ".":
4030 raise ValueError("no fractions separator")
4033 raise ValueError("trailing zero")
4036 raise ValueError("only microsecond fractions are supported")
4037 us = int(us + ("0" * (6 - us_len)))
4039 int(value[:4]), # %Y
4040 int(value[4:6]), # %m
4041 int(value[6:8]), # %d
4042 int(value[8:10]), # %H
4043 int(value[10:12]), # %M
4044 int(value[12:14]), # %S
4048 raise ValueError("invalid GeneralizedTime length")
4050 def _value_sanitize(self, value):
4051 if isinstance(value, binary_type):
4053 value_decoded = value.decode("ascii")
4054 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4055 raise DecodeError("invalid GeneralizedTime encoding: %r" % err)
4057 self._strptime(value_decoded)
4058 except (TypeError, ValueError) as err:
4060 "invalid GeneralizedTime format: %r" % err,
4061 klass=self.__class__,
4064 if isinstance(value, self.__class__):
4066 if isinstance(value, datetime):
4067 encoded = value.strftime("%Y%m%d%H%M%S")
4068 if value.microsecond > 0:
4069 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
4070 return (encoded + "Z").encode("ascii")
4071 raise InvalidValueType((self.__class__, datetime))
4073 def todatetime(self):
4074 return self._strptime(self._value.decode("ascii"))
4077 class GraphicString(CommonString):
4079 tag_default = tag_encode(25)
4080 encoding = "iso-8859-1"
4081 asn1_type_name = "GraphicString"
4084 class VisibleString(CommonString):
4086 tag_default = tag_encode(26)
4088 asn1_type_name = "VisibleString"
4091 class ISO646String(VisibleString):
4093 asn1_type_name = "ISO646String"
4096 class GeneralString(CommonString):
4098 tag_default = tag_encode(27)
4099 encoding = "iso-8859-1"
4100 asn1_type_name = "GeneralString"
4103 class UniversalString(CommonString):
4105 tag_default = tag_encode(28)
4106 encoding = "utf-32-be"
4107 asn1_type_name = "UniversalString"
4110 class BMPString(CommonString):
4112 tag_default = tag_encode(30)
4113 encoding = "utf-16-be"
4114 asn1_type_name = "BMPString"
4118 """``CHOICE`` special type
4122 class GeneralName(Choice):
4124 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4125 ("dNSName", IA5String(impl=tag_ctxp(2))),
4128 >>> gn = GeneralName()
4130 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4131 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4132 >>> gn["dNSName"] = IA5String("bar.baz")
4133 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4134 >>> gn["rfc822Name"]
4137 [2] IA5String IA5 bar.baz
4140 >>> gn.value == gn["dNSName"]
4143 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4145 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4146 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4148 __slots__ = ("specs",)
4150 asn1_type_name = "CHOICE"
4163 :param value: set the value. Either ``(choice, value)`` tuple, or
4164 :py:class:`pyderasn.Choice` object
4165 :param bytes impl: can not be set, do **not** use it
4166 :param bytes expl: override default tag with ``EXPLICIT`` one
4167 :param default: set default value. Type same as in ``value``
4168 :param bool optional: is object ``OPTIONAL`` in sequence
4170 if impl is not None:
4171 raise ValueError("no implicit tag allowed for CHOICE")
4172 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4174 schema = getattr(self, "schema", ())
4175 if len(schema) == 0:
4176 raise ValueError("schema must be specified")
4178 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4181 if value is not None:
4182 self._value = self._value_sanitize(value)
4183 if default is not None:
4184 default_value = self._value_sanitize(default)
4185 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4186 default_obj.specs = self.specs
4187 default_obj._value = default_value
4188 self.default = default_obj
4190 self._value = default_obj.copy()._value
4192 def _value_sanitize(self, value):
4193 if isinstance(value, tuple) and len(value) == 2:
4195 spec = self.specs.get(choice)
4197 raise ObjUnknown(choice)
4198 if not isinstance(obj, spec.__class__):
4199 raise InvalidValueType((spec,))
4200 return (choice, spec(obj))
4201 if isinstance(value, self.__class__):
4203 raise InvalidValueType((self.__class__, tuple))
4207 return self._value is not None and self._value[1].ready
4211 return self.expl_lenindef or (
4212 (self._value is not None) and
4213 self._value[1].bered
4217 obj = self.__class__(schema=self.specs)
4218 obj._expl = self._expl
4219 obj.default = self.default
4220 obj.optional = self.optional
4221 obj.offset = self.offset
4222 obj.llen = self.llen
4223 obj.vlen = self.vlen
4224 obj.expl_lenindef = self.expl_lenindef
4225 obj.lenindef = self.lenindef
4226 obj.ber_encoded = self.ber_encoded
4228 if value is not None:
4229 obj._value = (value[0], value[1].copy())
4232 def __eq__(self, their):
4233 if isinstance(their, tuple) and len(their) == 2:
4234 return self._value == their
4235 if not isinstance(their, self.__class__):
4238 self.specs == their.specs and
4239 self._value == their._value
4249 return self.__class__(
4252 expl=self._expl if expl is None else expl,
4253 default=self.default if default is None else default,
4254 optional=self.optional if optional is None else optional,
4259 self._assert_ready()
4260 return self._value[0]
4264 self._assert_ready()
4265 return self._value[1]
4267 def __getitem__(self, key):
4268 if key not in self.specs:
4269 raise ObjUnknown(key)
4270 if self._value is None:
4272 choice, value = self._value
4277 def __setitem__(self, key, value):
4278 spec = self.specs.get(key)
4280 raise ObjUnknown(key)
4281 if not isinstance(value, spec.__class__):
4282 raise InvalidValueType((spec.__class__,))
4283 self._value = (key, spec(value))
4291 return self._value[1].decoded if self.ready else False
4294 self._assert_ready()
4295 return self._value[1].encode()
4297 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4298 for choice, spec in iteritems(self.specs):
4299 sub_decode_path = decode_path + (choice,)
4305 decode_path=sub_decode_path,
4308 _ctx_immutable=False,
4315 klass=self.__class__,
4316 decode_path=decode_path,
4319 if tag_only: # pragma: no cover
4321 value, tail = spec.decode(
4325 decode_path=sub_decode_path,
4327 _ctx_immutable=False,
4329 obj = self.__class__(
4332 default=self.default,
4333 optional=self.optional,
4334 _decoded=(offset, 0, value.fulllen),
4336 obj._value = (choice, value)
4340 value = pp_console_row(next(self.pps()))
4342 value = "%s[%r]" % (value, self.value)
4345 def pps(self, decode_path=()):
4348 asn1_type_name=self.asn1_type_name,
4349 obj_name=self.__class__.__name__,
4350 decode_path=decode_path,
4351 value=self.choice if self.ready else None,
4352 optional=self.optional,
4353 default=self == self.default,
4354 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4355 expl=None if self._expl is None else tag_decode(self._expl),
4360 expl_lenindef=self.expl_lenindef,
4364 yield self.value.pps(decode_path=decode_path + (self.choice,))
4365 for pp in self.pps_lenindef(decode_path):
4369 class PrimitiveTypes(Choice):
4370 """Predefined ``CHOICE`` for all generic primitive types
4372 It could be useful for general decoding of some unspecified values:
4374 >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
4375 OCTET STRING 3 bytes 666f6f
4376 >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
4380 schema = tuple((klass.__name__, klass()) for klass in (
4405 """``ANY`` special type
4407 >>> Any(Integer(-123))
4409 >>> a = Any(OctetString(b"hello world").encode())
4410 ANY 040b68656c6c6f20776f726c64
4411 >>> hexenc(bytes(a))
4412 b'0x040x0bhello world'
4414 __slots__ = ("defined",)
4415 tag_default = tag_encode(0)
4416 asn1_type_name = "ANY"
4426 :param value: set the value. Either any kind of pyderasn's
4427 **ready** object, or bytes. Pay attention that
4428 **no** validation is performed is raw binary value
4430 :param bytes expl: override default tag with ``EXPLICIT`` one
4431 :param bool optional: is object ``OPTIONAL`` in sequence
4433 super(Any, self).__init__(None, expl, None, optional, _decoded)
4434 self._value = None if value is None else self._value_sanitize(value)
4437 def _value_sanitize(self, value):
4438 if isinstance(value, binary_type):
4440 if isinstance(value, self.__class__):
4442 if isinstance(value, Obj):
4443 return value.encode()
4444 raise InvalidValueType((self.__class__, Obj, binary_type))
4448 return self._value is not None
4452 if self.expl_lenindef or self.lenindef:
4454 if self.defined is None:
4456 return self.defined[1].bered
4459 obj = self.__class__()
4460 obj._value = self._value
4462 obj._expl = self._expl
4463 obj.optional = self.optional
4464 obj.offset = self.offset
4465 obj.llen = self.llen
4466 obj.vlen = self.vlen
4467 obj.expl_lenindef = self.expl_lenindef
4468 obj.lenindef = self.lenindef
4469 obj.ber_encoded = self.ber_encoded
4472 def __eq__(self, their):
4473 if isinstance(their, binary_type):
4474 return self._value == their
4475 if issubclass(their.__class__, Any):
4476 return self._value == their._value
4485 return self.__class__(
4487 expl=self._expl if expl is None else expl,
4488 optional=self.optional if optional is None else optional,
4491 def __bytes__(self):
4492 self._assert_ready()
4500 self._assert_ready()
4503 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4505 t, tlen, lv = tag_strip(tlv)
4506 except DecodeError as err:
4507 raise err.__class__(
4509 klass=self.__class__,
4510 decode_path=decode_path,
4514 l, llen, v = len_decode(lv)
4515 except LenIndefForm as err:
4516 if not ctx.get("bered", False):
4517 raise err.__class__(
4519 klass=self.__class__,
4520 decode_path=decode_path,
4523 llen, vlen, v = 1, 0, lv[1:]
4524 sub_offset = offset + tlen + llen
4526 while v[:EOC_LEN].tobytes() != EOC:
4527 chunk, v = Any().decode(
4530 decode_path=decode_path + (str(chunk_i),),
4533 _ctx_immutable=False,
4535 vlen += chunk.tlvlen
4536 sub_offset += chunk.tlvlen
4538 tlvlen = tlen + llen + vlen + EOC_LEN
4539 obj = self.__class__(
4540 value=tlv[:tlvlen].tobytes(),
4542 optional=self.optional,
4543 _decoded=(offset, 0, tlvlen),
4547 return obj, v[EOC_LEN:]
4548 except DecodeError as err:
4549 raise err.__class__(
4551 klass=self.__class__,
4552 decode_path=decode_path,
4556 raise NotEnoughData(
4557 "encoded length is longer than data",
4558 klass=self.__class__,
4559 decode_path=decode_path,
4562 tlvlen = tlen + llen + l
4563 v, tail = tlv[:tlvlen], v[l:]
4564 obj = self.__class__(
4567 optional=self.optional,
4568 _decoded=(offset, 0, tlvlen),
4574 return pp_console_row(next(self.pps()))
4576 def pps(self, decode_path=()):
4579 asn1_type_name=self.asn1_type_name,
4580 obj_name=self.__class__.__name__,
4581 decode_path=decode_path,
4582 blob=self._value if self.ready else None,
4583 optional=self.optional,
4584 default=self == self.default,
4585 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4586 expl=None if self._expl is None else tag_decode(self._expl),
4591 expl_offset=self.expl_offset if self.expled else None,
4592 expl_tlen=self.expl_tlen if self.expled else None,
4593 expl_llen=self.expl_llen if self.expled else None,
4594 expl_vlen=self.expl_vlen if self.expled else None,
4595 expl_lenindef=self.expl_lenindef,
4596 lenindef=self.lenindef,
4599 defined_by, defined = self.defined or (None, None)
4600 if defined_by is not None:
4602 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4604 for pp in self.pps_lenindef(decode_path):
4608 ########################################################################
4609 # ASN.1 constructed types
4610 ########################################################################
4612 def get_def_by_path(defines_by_path, sub_decode_path):
4613 """Get define by decode path
4615 for path, define in defines_by_path:
4616 if len(path) != len(sub_decode_path):
4618 for p1, p2 in zip(path, sub_decode_path):
4619 if (p1 != any) and (p1 != p2):
4625 def abs_decode_path(decode_path, rel_path):
4626 """Create an absolute decode path from current and relative ones
4628 :param decode_path: current decode path, starting point. Tuple of strings
4629 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4630 If first tuple's element is "/", then treat it as
4631 an absolute path, ignoring ``decode_path`` as
4632 starting point. Also this tuple can contain ".."
4633 elements, stripping the leading element from
4636 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4637 ("foo", "bar", "baz", "whatever")
4638 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4640 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4643 if rel_path[0] == "/":
4645 if rel_path[0] == "..":
4646 return abs_decode_path(decode_path[:-1], rel_path[1:])
4647 return decode_path + rel_path
4650 class Sequence(Obj):
4651 """``SEQUENCE`` structure type
4653 You have to make specification of sequence::
4655 class Extension(Sequence):
4657 ("extnID", ObjectIdentifier()),
4658 ("critical", Boolean(default=False)),
4659 ("extnValue", OctetString()),
4662 Then, you can work with it as with dictionary.
4664 >>> ext = Extension()
4665 >>> Extension().specs
4667 ('extnID', OBJECT IDENTIFIER),
4668 ('critical', BOOLEAN False OPTIONAL DEFAULT),
4669 ('extnValue', OCTET STRING),
4671 >>> ext["extnID"] = "1.2.3"
4672 Traceback (most recent call last):
4673 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
4674 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
4676 You can determine if sequence is ready to be encoded:
4681 Traceback (most recent call last):
4682 pyderasn.ObjNotReady: object is not ready: extnValue
4683 >>> ext["extnValue"] = OctetString(b"foobar")
4687 Value you want to assign, must have the same **type** as in
4688 corresponding specification, but it can have different tags,
4689 optional/default attributes -- they will be taken from specification
4692 class TBSCertificate(Sequence):
4694 ("version", Version(expl=tag_ctxc(0), default="v1")),
4697 >>> tbs = TBSCertificate()
4698 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
4700 Assign ``None`` to remove value from sequence.
4702 You can set values in Sequence during its initialization:
4704 >>> AlgorithmIdentifier((
4705 ("algorithm", ObjectIdentifier("1.2.3")),
4706 ("parameters", Any(Null()))
4708 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
4710 You can determine if value exists/set in the sequence and take its value:
4712 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
4715 OBJECT IDENTIFIER 1.2.3
4717 But pay attention that if value has default, then it won't be (not
4718 in) in the sequence (because ``DEFAULT`` must not be encoded in
4719 DER), but you can read its value:
4721 >>> "critical" in ext, ext["critical"]
4722 (False, BOOLEAN False)
4723 >>> ext["critical"] = Boolean(True)
4724 >>> "critical" in ext, ext["critical"]
4725 (True, BOOLEAN True)
4727 All defaulted values are always optional.
4729 .. _allow_default_values_ctx:
4731 DER prohibits default value encoding and will raise an error if
4732 default value is unexpectedly met during decode.
4733 If :ref:`bered <bered_ctx>` context option is set, then no error
4734 will be raised, but ``bered`` attribute set. You can disable strict
4735 defaulted values existence validation by setting
4736 ``"allow_default_values": True`` :ref:`context <ctx>` option.
4738 Two sequences are equal if they have equal specification (schema),
4739 implicit/explicit tagging and the same values.
4741 __slots__ = ("specs",)
4742 tag_default = tag_encode(form=TagFormConstructed, num=16)
4743 asn1_type_name = "SEQUENCE"
4755 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
4757 schema = getattr(self, "schema", ())
4759 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4762 if value is not None:
4763 if issubclass(value.__class__, Sequence):
4764 self._value = value._value
4765 elif hasattr(value, "__iter__"):
4766 for seq_key, seq_value in value:
4767 self[seq_key] = seq_value
4769 raise InvalidValueType((Sequence,))
4770 if default is not None:
4771 if not issubclass(default.__class__, Sequence):
4772 raise InvalidValueType((Sequence,))
4773 default_value = default._value
4774 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4775 default_obj.specs = self.specs
4776 default_obj._value = default_value
4777 self.default = default_obj
4779 self._value = default_obj.copy()._value
4783 for name, spec in iteritems(self.specs):
4784 value = self._value.get(name)
4795 if self.expl_lenindef or self.lenindef or self.ber_encoded:
4797 return any(value.bered for value in itervalues(self._value))
4800 obj = self.__class__(schema=self.specs)
4802 obj._expl = self._expl
4803 obj.default = self.default
4804 obj.optional = self.optional
4805 obj.offset = self.offset
4806 obj.llen = self.llen
4807 obj.vlen = self.vlen
4808 obj.expl_lenindef = self.expl_lenindef
4809 obj.lenindef = self.lenindef
4810 obj.ber_encoded = self.ber_encoded
4811 obj._value = {k: v.copy() for k, v in iteritems(self._value)}
4814 def __eq__(self, their):
4815 if not isinstance(their, self.__class__):
4818 self.specs == their.specs and
4819 self.tag == their.tag and
4820 self._expl == their._expl and
4821 self._value == their._value
4832 return self.__class__(
4835 impl=self.tag if impl is None else impl,
4836 expl=self._expl if expl is None else expl,
4837 default=self.default if default is None else default,
4838 optional=self.optional if optional is None else optional,
4841 def __contains__(self, key):
4842 return key in self._value
4844 def __setitem__(self, key, value):
4845 spec = self.specs.get(key)
4847 raise ObjUnknown(key)
4849 self._value.pop(key, None)
4851 if not isinstance(value, spec.__class__):
4852 raise InvalidValueType((spec.__class__,))
4853 value = spec(value=value)
4854 if spec.default is not None and value == spec.default:
4855 self._value.pop(key, None)
4857 self._value[key] = value
4859 def __getitem__(self, key):
4860 value = self._value.get(key)
4861 if value is not None:
4863 spec = self.specs.get(key)
4865 raise ObjUnknown(key)
4866 if spec.default is not None:
4870 def _encoded_values(self):
4872 for name, spec in iteritems(self.specs):
4873 value = self._value.get(name)
4877 raise ObjNotReady(name)
4878 raws.append(value.encode())
4882 v = b"".join(self._encoded_values())
4883 return b"".join((self.tag, len_encode(len(v)), v))
4885 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4887 t, tlen, lv = tag_strip(tlv)
4888 except DecodeError as err:
4889 raise err.__class__(
4891 klass=self.__class__,
4892 decode_path=decode_path,
4897 klass=self.__class__,
4898 decode_path=decode_path,
4901 if tag_only: # pragma: no cover
4904 ctx_bered = ctx.get("bered", False)
4906 l, llen, v = len_decode(lv)
4907 except LenIndefForm as err:
4909 raise err.__class__(
4911 klass=self.__class__,
4912 decode_path=decode_path,
4915 l, llen, v = 0, 1, lv[1:]
4917 except DecodeError as err:
4918 raise err.__class__(
4920 klass=self.__class__,
4921 decode_path=decode_path,
4925 raise NotEnoughData(
4926 "encoded length is longer than data",
4927 klass=self.__class__,
4928 decode_path=decode_path,
4932 v, tail = v[:l], v[l:]
4934 sub_offset = offset + tlen + llen
4937 ctx_allow_default_values = ctx.get("allow_default_values", False)
4938 for name, spec in iteritems(self.specs):
4939 if spec.optional and (
4940 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
4944 sub_decode_path = decode_path + (name,)
4946 value, v_tail = spec.decode(
4950 decode_path=sub_decode_path,
4952 _ctx_immutable=False,
4954 except TagMismatch as err:
4955 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
4959 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
4960 if defined is not None:
4961 defined_by, defined_spec = defined
4962 if issubclass(value.__class__, SequenceOf):
4963 for i, _value in enumerate(value):
4964 sub_sub_decode_path = sub_decode_path + (
4966 DecodePathDefBy(defined_by),
4968 defined_value, defined_tail = defined_spec.decode(
4969 memoryview(bytes(_value)),
4971 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4972 if value.expled else (value.tlen + value.llen)
4975 decode_path=sub_sub_decode_path,
4977 _ctx_immutable=False,
4979 if len(defined_tail) > 0:
4982 klass=self.__class__,
4983 decode_path=sub_sub_decode_path,
4986 _value.defined = (defined_by, defined_value)
4988 defined_value, defined_tail = defined_spec.decode(
4989 memoryview(bytes(value)),
4991 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4992 if value.expled else (value.tlen + value.llen)
4995 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4997 _ctx_immutable=False,
4999 if len(defined_tail) > 0:
5002 klass=self.__class__,
5003 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5006 value.defined = (defined_by, defined_value)
5008 value_len = value.fulllen
5010 sub_offset += value_len
5012 if spec.default is not None and value == spec.default:
5013 if ctx_bered or ctx_allow_default_values:
5017 "DEFAULT value met",
5018 klass=self.__class__,
5019 decode_path=sub_decode_path,
5022 values[name] = value
5024 spec_defines = getattr(spec, "defines", ())
5025 if len(spec_defines) == 0:
5026 defines_by_path = ctx.get("defines_by_path", ())
5027 if len(defines_by_path) > 0:
5028 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5029 if spec_defines is not None and len(spec_defines) > 0:
5030 for rel_path, schema in spec_defines:
5031 defined = schema.get(value, None)
5032 if defined is not None:
5033 ctx.setdefault("_defines", []).append((
5034 abs_decode_path(sub_decode_path[:-1], rel_path),
5038 if v[:EOC_LEN].tobytes() != EOC:
5041 klass=self.__class__,
5042 decode_path=decode_path,
5050 klass=self.__class__,
5051 decode_path=decode_path,
5054 obj = self.__class__(
5058 default=self.default,
5059 optional=self.optional,
5060 _decoded=(offset, llen, vlen),
5063 obj.lenindef = lenindef
5064 obj.ber_encoded = ber_encoded
5068 value = pp_console_row(next(self.pps()))
5070 for name in self.specs:
5071 _value = self._value.get(name)
5074 cols.append("%s: %s" % (name, repr(_value)))
5075 return "%s[%s]" % (value, "; ".join(cols))
5077 def pps(self, decode_path=()):
5080 asn1_type_name=self.asn1_type_name,
5081 obj_name=self.__class__.__name__,
5082 decode_path=decode_path,
5083 optional=self.optional,
5084 default=self == self.default,
5085 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5086 expl=None if self._expl is None else tag_decode(self._expl),
5091 expl_offset=self.expl_offset if self.expled else None,
5092 expl_tlen=self.expl_tlen if self.expled else None,
5093 expl_llen=self.expl_llen if self.expled else None,
5094 expl_vlen=self.expl_vlen if self.expled else None,
5095 expl_lenindef=self.expl_lenindef,
5096 lenindef=self.lenindef,
5097 ber_encoded=self.ber_encoded,
5100 for name in self.specs:
5101 value = self._value.get(name)
5104 yield value.pps(decode_path=decode_path + (name,))
5105 for pp in self.pps_lenindef(decode_path):
5109 class Set(Sequence):
5110 """``SET`` structure type
5112 Its usage is identical to :py:class:`pyderasn.Sequence`.
5114 .. _allow_unordered_set_ctx:
5116 DER prohibits unordered values encoding and will raise an error
5117 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5118 then no error will occure. Also you can disable strict values
5119 ordering check by setting ``"allow_unordered_set": True``
5120 :ref:`context <ctx>` option.
5123 tag_default = tag_encode(form=TagFormConstructed, num=17)
5124 asn1_type_name = "SET"
5127 raws = self._encoded_values()
5130 return b"".join((self.tag, len_encode(len(v)), v))
5132 def _specs_items(self):
5133 return iteritems(self.specs)
5135 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5137 t, tlen, lv = tag_strip(tlv)
5138 except DecodeError as err:
5139 raise err.__class__(
5141 klass=self.__class__,
5142 decode_path=decode_path,
5147 klass=self.__class__,
5148 decode_path=decode_path,
5154 ctx_bered = ctx.get("bered", False)
5156 l, llen, v = len_decode(lv)
5157 except LenIndefForm as err:
5159 raise err.__class__(
5161 klass=self.__class__,
5162 decode_path=decode_path,
5165 l, llen, v = 0, 1, lv[1:]
5167 except DecodeError as err:
5168 raise err.__class__(
5170 klass=self.__class__,
5171 decode_path=decode_path,
5175 raise NotEnoughData(
5176 "encoded length is longer than data",
5177 klass=self.__class__,
5181 v, tail = v[:l], v[l:]
5183 sub_offset = offset + tlen + llen
5186 ctx_allow_default_values = ctx.get("allow_default_values", False)
5187 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5188 value_prev = memoryview(v[:0])
5191 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5193 for name, spec in self._specs_items():
5194 sub_decode_path = decode_path + (name,)
5200 decode_path=sub_decode_path,
5203 _ctx_immutable=False,
5210 klass=self.__class__,
5211 decode_path=decode_path,
5214 value, v_tail = spec.decode(
5218 decode_path=sub_decode_path,
5220 _ctx_immutable=False,
5222 value_len = value.fulllen
5223 if value_prev.tobytes() > v[:value_len].tobytes():
5224 if ctx_bered or ctx_allow_unordered_set:
5228 "unordered " + self.asn1_type_name,
5229 klass=self.__class__,
5230 decode_path=sub_decode_path,
5233 if spec.default is None or value != spec.default:
5235 elif ctx_bered or ctx_allow_default_values:
5239 "DEFAULT value met",
5240 klass=self.__class__,
5241 decode_path=sub_decode_path,
5244 values[name] = value
5245 value_prev = v[:value_len]
5246 sub_offset += value_len
5249 obj = self.__class__(
5253 default=self.default,
5254 optional=self.optional,
5255 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5258 if v[:EOC_LEN].tobytes() != EOC:
5261 klass=self.__class__,
5262 decode_path=decode_path,
5270 "not all values are ready",
5271 klass=self.__class__,
5272 decode_path=decode_path,
5275 obj.ber_encoded = ber_encoded
5279 class SequenceOf(Obj):
5280 """``SEQUENCE OF`` sequence type
5282 For that kind of type you must specify the object it will carry on
5283 (bounds are for example here, not required)::
5285 class Ints(SequenceOf):
5290 >>> ints.append(Integer(123))
5291 >>> ints.append(Integer(234))
5293 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5294 >>> [int(i) for i in ints]
5296 >>> ints.append(Integer(345))
5297 Traceback (most recent call last):
5298 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5301 >>> ints[1] = Integer(345)
5303 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5305 Also you can initialize sequence with preinitialized values:
5307 >>> ints = Ints([Integer(123), Integer(234)])
5309 __slots__ = ("spec", "_bound_min", "_bound_max")
5310 tag_default = tag_encode(form=TagFormConstructed, num=16)
5311 asn1_type_name = "SEQUENCE OF"
5324 super(SequenceOf, self).__init__(
5332 schema = getattr(self, "schema", None)
5334 raise ValueError("schema must be specified")
5336 self._bound_min, self._bound_max = getattr(
5340 ) if bounds is None else bounds
5342 if value is not None:
5343 self._value = self._value_sanitize(value)
5344 if default is not None:
5345 default_value = self._value_sanitize(default)
5346 default_obj = self.__class__(
5351 default_obj._value = default_value
5352 self.default = default_obj
5354 self._value = default_obj.copy()._value
5356 def _value_sanitize(self, value):
5357 if issubclass(value.__class__, SequenceOf):
5358 value = value._value
5359 elif hasattr(value, "__iter__"):
5362 raise InvalidValueType((self.__class__, iter))
5363 if not self._bound_min <= len(value) <= self._bound_max:
5364 raise BoundsError(self._bound_min, len(value), self._bound_max)
5366 if not isinstance(v, self.spec.__class__):
5367 raise InvalidValueType((self.spec.__class__,))
5372 return all(v.ready for v in self._value)
5376 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5378 return any(v.bered for v in self._value)
5381 obj = self.__class__(schema=self.spec)
5382 obj._bound_min = self._bound_min
5383 obj._bound_max = self._bound_max
5385 obj._expl = self._expl
5386 obj.default = self.default
5387 obj.optional = self.optional
5388 obj.offset = self.offset
5389 obj.llen = self.llen
5390 obj.vlen = self.vlen
5391 obj.expl_lenindef = self.expl_lenindef
5392 obj.lenindef = self.lenindef
5393 obj.ber_encoded = self.ber_encoded
5394 obj._value = [v.copy() for v in self._value]
5397 def __eq__(self, their):
5398 if isinstance(their, self.__class__):
5400 self.spec == their.spec and
5401 self.tag == their.tag and
5402 self._expl == their._expl and
5403 self._value == their._value
5405 if hasattr(their, "__iter__"):
5406 return self._value == list(their)
5418 return self.__class__(
5422 (self._bound_min, self._bound_max)
5423 if bounds is None else bounds
5425 impl=self.tag if impl is None else impl,
5426 expl=self._expl if expl is None else expl,
5427 default=self.default if default is None else default,
5428 optional=self.optional if optional is None else optional,
5431 def __contains__(self, key):
5432 return key in self._value
5434 def append(self, value):
5435 if not isinstance(value, self.spec.__class__):
5436 raise InvalidValueType((self.spec.__class__,))
5437 if len(self._value) + 1 > self._bound_max:
5440 len(self._value) + 1,
5443 self._value.append(value)
5446 self._assert_ready()
5447 return iter(self._value)
5450 self._assert_ready()
5451 return len(self._value)
5453 def __setitem__(self, key, value):
5454 if not isinstance(value, self.spec.__class__):
5455 raise InvalidValueType((self.spec.__class__,))
5456 self._value[key] = self.spec(value=value)
5458 def __getitem__(self, key):
5459 return self._value[key]
5461 def _encoded_values(self):
5462 return [v.encode() for v in self._value]
5465 v = b"".join(self._encoded_values())
5466 return b"".join((self.tag, len_encode(len(v)), v))
5468 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5470 t, tlen, lv = tag_strip(tlv)
5471 except DecodeError as err:
5472 raise err.__class__(
5474 klass=self.__class__,
5475 decode_path=decode_path,
5480 klass=self.__class__,
5481 decode_path=decode_path,
5487 ctx_bered = ctx.get("bered", False)
5489 l, llen, v = len_decode(lv)
5490 except LenIndefForm as err:
5492 raise err.__class__(
5494 klass=self.__class__,
5495 decode_path=decode_path,
5498 l, llen, v = 0, 1, lv[1:]
5500 except DecodeError as err:
5501 raise err.__class__(
5503 klass=self.__class__,
5504 decode_path=decode_path,
5508 raise NotEnoughData(
5509 "encoded length is longer than data",
5510 klass=self.__class__,
5511 decode_path=decode_path,
5515 v, tail = v[:l], v[l:]
5517 sub_offset = offset + tlen + llen
5519 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5520 value_prev = memoryview(v[:0])
5524 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5526 sub_decode_path = decode_path + (str(len(_value)),)
5527 value, v_tail = spec.decode(
5531 decode_path=sub_decode_path,
5533 _ctx_immutable=False,
5535 value_len = value.fulllen
5537 if value_prev.tobytes() > v[:value_len].tobytes():
5538 if ctx_bered or ctx_allow_unordered_set:
5542 "unordered " + self.asn1_type_name,
5543 klass=self.__class__,
5544 decode_path=sub_decode_path,
5547 value_prev = v[:value_len]
5548 _value.append(value)
5549 sub_offset += value_len
5553 obj = self.__class__(
5556 bounds=(self._bound_min, self._bound_max),
5559 default=self.default,
5560 optional=self.optional,
5561 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5563 except BoundsError as err:
5566 klass=self.__class__,
5567 decode_path=decode_path,
5571 if v[:EOC_LEN].tobytes() != EOC:
5574 klass=self.__class__,
5575 decode_path=decode_path,
5580 obj.ber_encoded = ber_encoded
5585 pp_console_row(next(self.pps())),
5586 ", ".join(repr(v) for v in self._value),
5589 def pps(self, decode_path=()):
5592 asn1_type_name=self.asn1_type_name,
5593 obj_name=self.__class__.__name__,
5594 decode_path=decode_path,
5595 optional=self.optional,
5596 default=self == self.default,
5597 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5598 expl=None if self._expl is None else tag_decode(self._expl),
5603 expl_offset=self.expl_offset if self.expled else None,
5604 expl_tlen=self.expl_tlen if self.expled else None,
5605 expl_llen=self.expl_llen if self.expled else None,
5606 expl_vlen=self.expl_vlen if self.expled else None,
5607 expl_lenindef=self.expl_lenindef,
5608 lenindef=self.lenindef,
5609 ber_encoded=self.ber_encoded,
5612 for i, value in enumerate(self._value):
5613 yield value.pps(decode_path=decode_path + (str(i),))
5614 for pp in self.pps_lenindef(decode_path):
5618 class SetOf(SequenceOf):
5619 """``SET OF`` sequence type
5621 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
5624 tag_default = tag_encode(form=TagFormConstructed, num=17)
5625 asn1_type_name = "SET OF"
5628 raws = self._encoded_values()
5631 return b"".join((self.tag, len_encode(len(v)), v))
5633 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5634 return super(SetOf, self)._decode(
5640 ordering_check=True,
5644 def obj_by_path(pypath): # pragma: no cover
5645 """Import object specified as string Python path
5647 Modules must be separated from classes/functions with ``:``.
5649 >>> obj_by_path("foo.bar:Baz")
5650 <class 'foo.bar.Baz'>
5651 >>> obj_by_path("foo.bar:Baz.boo")
5652 <classmethod 'foo.bar.Baz.boo'>
5654 mod, objs = pypath.rsplit(":", 1)
5655 from importlib import import_module
5656 obj = import_module(mod)
5657 for obj_name in objs.split("."):
5658 obj = getattr(obj, obj_name)
5662 def generic_decoder(): # pragma: no cover
5663 # All of this below is a big hack with self references
5664 choice = PrimitiveTypes()
5665 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
5666 choice.specs["SetOf"] = SetOf(schema=choice)
5667 for i in six_xrange(31):
5668 choice.specs["SequenceOf%d" % i] = SequenceOf(
5672 choice.specs["Any"] = Any()
5674 # Class name equals to type name, to omit it from output
5675 class SEQUENCEOF(SequenceOf):
5683 with_decode_path=False,
5684 decode_path_only=(),
5686 def _pprint_pps(pps):
5688 if hasattr(pp, "_fields"):
5690 decode_path_only != () and
5691 pp.decode_path[:len(decode_path_only)] != decode_path_only
5694 if pp.asn1_type_name == Choice.asn1_type_name:
5696 pp_kwargs = pp._asdict()
5697 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
5698 pp = _pp(**pp_kwargs)
5699 yield pp_console_row(
5704 with_colours=with_colours,
5705 with_decode_path=with_decode_path,
5706 decode_path_len_decrease=len(decode_path_only),
5708 for row in pp_console_blob(
5710 decode_path_len_decrease=len(decode_path_only),
5714 for row in _pprint_pps(pp):
5716 return "\n".join(_pprint_pps(obj.pps()))
5717 return SEQUENCEOF(), pprint_any
5720 def main(): # pragma: no cover
5722 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
5723 parser.add_argument(
5727 help="Skip that number of bytes from the beginning",
5729 parser.add_argument(
5731 help="Python paths to dictionary with OIDs, comma separated",
5733 parser.add_argument(
5735 help="Python path to schema definition to use",
5737 parser.add_argument(
5738 "--defines-by-path",
5739 help="Python path to decoder's defines_by_path",
5741 parser.add_argument(
5743 action="store_true",
5744 help="Disallow BER encoding",
5746 parser.add_argument(
5747 "--print-decode-path",
5748 action="store_true",
5749 help="Print decode paths",
5751 parser.add_argument(
5752 "--decode-path-only",
5753 help="Print only specified decode path",
5755 parser.add_argument(
5757 action="store_true",
5758 help="Allow explicit tag out-of-bound",
5760 parser.add_argument(
5762 type=argparse.FileType("rb"),
5763 help="Path to DER file you want to decode",
5765 args = parser.parse_args()
5766 args.DERFile.seek(args.skip)
5767 der = memoryview(args.DERFile.read())
5768 args.DERFile.close()
5770 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
5771 if args.oids else ()
5774 schema = obj_by_path(args.schema)
5775 from functools import partial
5776 pprinter = partial(pprint, big_blobs=True)
5778 schema, pprinter = generic_decoder()
5780 "bered": not args.nobered,
5781 "allow_expl_oob": args.allow_expl_oob,
5783 if args.defines_by_path is not None:
5784 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
5785 obj, tail = schema().decode(der, ctx=ctx)
5789 with_colours=environ.get("NO_COLOR") is None,
5790 with_decode_path=args.print_decode_path,
5792 () if args.decode_path_only is None else
5793 tuple(args.decode_path_only.split(":"))
5797 print("\nTrailing data: %s" % hexenc(tail))
5800 if __name__ == "__main__":