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.
525 .. autoclass:: pyderasn.Boolean
530 .. autoclass:: pyderasn.Integer
535 .. autoclass:: pyderasn.BitString
540 .. autoclass:: pyderasn.OctetString
545 .. autoclass:: pyderasn.Null
550 .. autoclass:: pyderasn.ObjectIdentifier
555 .. autoclass:: pyderasn.Enumerated
559 .. autoclass:: pyderasn.CommonString
563 .. autoclass:: pyderasn.NumericString
567 .. autoclass:: pyderasn.PrintableString
571 .. autoclass:: pyderasn.UTCTime
572 :members: __init__, todatetime
576 .. autoclass:: pyderasn.GeneralizedTime
583 .. autoclass:: pyderasn.Choice
588 .. autoclass:: PrimitiveTypes
592 .. autoclass:: pyderasn.Any
600 .. autoclass:: pyderasn.Sequence
605 .. autoclass:: pyderasn.Set
610 .. autoclass:: pyderasn.SequenceOf
615 .. autoclass:: pyderasn.SetOf
621 .. autofunction:: pyderasn.abs_decode_path
622 .. autofunction:: pyderasn.colonize_hex
623 .. autofunction:: pyderasn.hexenc
624 .. autofunction:: pyderasn.hexdec
625 .. autofunction:: pyderasn.tag_encode
626 .. autofunction:: pyderasn.tag_decode
627 .. autofunction:: pyderasn.tag_ctxp
628 .. autofunction:: pyderasn.tag_ctxc
629 .. autoclass:: pyderasn.Obj
630 .. autoclass:: pyderasn.DecodeError
632 .. autoclass:: pyderasn.NotEnoughData
633 .. autoclass:: pyderasn.LenIndefForm
634 .. autoclass:: pyderasn.TagMismatch
635 .. autoclass:: pyderasn.InvalidLength
636 .. autoclass:: pyderasn.InvalidOID
637 .. autoclass:: pyderasn.ObjUnknown
638 .. autoclass:: pyderasn.ObjNotReady
639 .. autoclass:: pyderasn.InvalidValueType
640 .. autoclass:: pyderasn.BoundsError
643 from codecs import getdecoder
644 from codecs import getencoder
645 from collections import namedtuple
646 from collections import OrderedDict
647 from copy import copy
648 from datetime import datetime
649 from math import ceil
650 from os import environ
651 from string import ascii_letters
652 from string import digits
654 from six import add_metaclass
655 from six import binary_type
656 from six import byte2int
657 from six import indexbytes
658 from six import int2byte
659 from six import integer_types
660 from six import iterbytes
661 from six import iteritems
662 from six import itervalues
664 from six import string_types
665 from six import text_type
666 from six import unichr as six_unichr
667 from six.moves import xrange as six_xrange
671 from termcolor import colored
672 except ImportError: # pragma: no cover
673 def colored(what, *args, **kwargs):
718 "TagClassApplication",
722 "TagFormConstructed",
733 TagClassUniversal = 0
734 TagClassApplication = 1 << 6
735 TagClassContext = 1 << 7
736 TagClassPrivate = 1 << 6 | 1 << 7
738 TagFormConstructed = 1 << 5
741 TagClassApplication: "APPLICATION ",
742 TagClassPrivate: "PRIVATE ",
743 TagClassUniversal: "UNIV ",
747 LENINDEF = b"\x80" # length indefinite mark
748 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
751 ########################################################################
753 ########################################################################
755 class ASN1Error(ValueError):
759 class DecodeError(ASN1Error):
760 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
762 :param str msg: reason of decode failing
763 :param klass: optional exact DecodeError inherited class (like
764 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
765 :py:exc:`InvalidLength`)
766 :param decode_path: tuple of strings. It contains human
767 readable names of the fields through which
768 decoding process has passed
769 :param int offset: binary offset where failure happened
771 super(DecodeError, self).__init__()
774 self.decode_path = decode_path
780 "" if self.klass is None else self.klass.__name__,
782 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
783 if len(self.decode_path) > 0 else ""
785 ("(at %d)" % self.offset) if self.offset > 0 else "",
791 return "%s(%s)" % (self.__class__.__name__, self)
794 class NotEnoughData(DecodeError):
798 class LenIndefForm(DecodeError):
802 class TagMismatch(DecodeError):
806 class InvalidLength(DecodeError):
810 class InvalidOID(DecodeError):
814 class ObjUnknown(ASN1Error):
815 def __init__(self, name):
816 super(ObjUnknown, self).__init__()
820 return "object is unknown: %s" % self.name
823 return "%s(%s)" % (self.__class__.__name__, self)
826 class ObjNotReady(ASN1Error):
827 def __init__(self, name):
828 super(ObjNotReady, self).__init__()
832 return "object is not ready: %s" % self.name
835 return "%s(%s)" % (self.__class__.__name__, self)
838 class InvalidValueType(ASN1Error):
839 def __init__(self, expected_types):
840 super(InvalidValueType, self).__init__()
841 self.expected_types = expected_types
844 return "invalid value type, expected: %s" % ", ".join(
845 [repr(t) for t in self.expected_types]
849 return "%s(%s)" % (self.__class__.__name__, self)
852 class BoundsError(ASN1Error):
853 def __init__(self, bound_min, value, bound_max):
854 super(BoundsError, self).__init__()
855 self.bound_min = bound_min
857 self.bound_max = bound_max
860 return "unsatisfied bounds: %s <= %s <= %s" % (
867 return "%s(%s)" % (self.__class__.__name__, self)
870 ########################################################################
872 ########################################################################
874 _hexdecoder = getdecoder("hex")
875 _hexencoder = getencoder("hex")
879 """Binary data to hexadecimal string convert
881 return _hexdecoder(data)[0]
885 """Hexadecimal string to binary data convert
887 return _hexencoder(data)[0].decode("ascii")
890 def int_bytes_len(num, byte_len=8):
893 return int(ceil(float(num.bit_length()) / byte_len))
896 def zero_ended_encode(num):
897 octets = bytearray(int_bytes_len(num, 7))
899 octets[i] = num & 0x7F
903 octets[i] = 0x80 | (num & 0x7F)
909 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
910 """Encode tag to binary form
912 :param int num: tag's number
913 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
914 :py:data:`pyderasn.TagClassContext`,
915 :py:data:`pyderasn.TagClassApplication`,
916 :py:data:`pyderasn.TagClassPrivate`)
917 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
918 :py:data:`pyderasn.TagFormConstructed`)
922 return int2byte(klass | form | num)
923 # [XX|X|11111][1.......][1.......] ... [0.......]
924 return int2byte(klass | form | 31) + zero_ended_encode(num)
928 """Decode tag from binary form
932 No validation is performed, assuming that it has already passed.
934 It returns tuple with three integers, as
935 :py:func:`pyderasn.tag_encode` accepts.
937 first_octet = byte2int(tag)
938 klass = first_octet & 0xC0
939 form = first_octet & 0x20
940 if first_octet & 0x1F < 0x1F:
941 return (klass, form, first_octet & 0x1F)
943 for octet in iterbytes(tag[1:]):
946 return (klass, form, num)
950 """Create CONTEXT PRIMITIVE tag
952 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
956 """Create CONTEXT CONSTRUCTED tag
958 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
962 """Take off tag from the data
964 :returns: (encoded tag, tag length, remaining data)
967 raise NotEnoughData("no data at all")
968 if byte2int(data) & 0x1F < 31:
969 return data[:1], 1, data[1:]
974 raise DecodeError("unfinished tag")
975 if indexbytes(data, i) & 0x80 == 0:
978 return data[:i], i, data[i:]
984 octets = bytearray(int_bytes_len(l) + 1)
985 octets[0] = 0x80 | (len(octets) - 1)
986 for i in six_xrange(len(octets) - 1, 0, -1):
992 def len_decode(data):
995 :returns: (decoded length, length's length, remaining data)
996 :raises LenIndefForm: if indefinite form encoding is met
999 raise NotEnoughData("no data at all")
1000 first_octet = byte2int(data)
1001 if first_octet & 0x80 == 0:
1002 return first_octet, 1, data[1:]
1003 octets_num = first_octet & 0x7F
1004 if octets_num + 1 > len(data):
1005 raise NotEnoughData("encoded length is longer than data")
1007 raise LenIndefForm()
1008 if byte2int(data[1:]) == 0:
1009 raise DecodeError("leading zeros")
1011 for v in iterbytes(data[1:1 + octets_num]):
1014 raise DecodeError("long form instead of short one")
1015 return l, 1 + octets_num, data[1 + octets_num:]
1018 ########################################################################
1020 ########################################################################
1022 class AutoAddSlots(type):
1023 def __new__(mcs, name, bases, _dict):
1024 _dict["__slots__"] = _dict.get("__slots__", ())
1025 return type.__new__(mcs, name, bases, _dict)
1028 @add_metaclass(AutoAddSlots)
1030 """Common ASN.1 object class
1032 All ASN.1 types are inherited from it. It has metaclass that
1033 automatically adds ``__slots__`` to all inherited classes.
1057 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1058 self._expl = getattr(self, "expl", None) if expl is None else expl
1059 if self.tag != self.tag_default and self._expl is not None:
1060 raise ValueError("implicit and explicit tags can not be set simultaneously")
1061 if default is not None:
1063 self.optional = optional
1064 self.offset, self.llen, self.vlen = _decoded
1066 self.expl_lenindef = False
1067 self.lenindef = False
1068 self.ber_encoded = False
1071 def ready(self): # pragma: no cover
1072 """Is object ready to be encoded?
1074 raise NotImplementedError()
1076 def _assert_ready(self):
1078 raise ObjNotReady(self.__class__.__name__)
1082 """Is either object or any elements inside is BER encoded?
1084 return self.expl_lenindef or self.lenindef or self.ber_encoded
1088 """Is object decoded?
1090 return (self.llen + self.vlen) > 0
1092 def copy(self): # pragma: no cover
1093 """Make a copy of object, safe to be mutated
1095 raise NotImplementedError()
1099 return len(self.tag)
1103 return self.tlen + self.llen + self.vlen
1105 def __str__(self): # pragma: no cover
1106 return self.__bytes__() if PY2 else self.__unicode__()
1108 def __ne__(self, their):
1109 return not(self == their)
1111 def __gt__(self, their): # pragma: no cover
1112 return not(self < their)
1114 def __le__(self, their): # pragma: no cover
1115 return (self == their) or (self < their)
1117 def __ge__(self, their): # pragma: no cover
1118 return (self == their) or (self > their)
1120 def _encode(self): # pragma: no cover
1121 raise NotImplementedError()
1123 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1124 raise NotImplementedError()
1127 raw = self._encode()
1128 if self._expl is None:
1130 return b"".join((self._expl, len_encode(len(raw)), raw))
1140 _ctx_immutable=True,
1144 :param data: either binary or memoryview
1145 :param int offset: initial data's offset
1146 :param bool leavemm: do we need to leave memoryview of remaining
1147 data as is, or convert it to bytes otherwise
1148 :param ctx: optional :ref:`context <ctx>` governing decoding process
1149 :param tag_only: decode only the tag, without length and contents
1150 (used only in Choice and Set structures, trying to
1151 determine if tag satisfies the scheme)
1152 :param _ctx_immutable: do we need to copy ``ctx`` before using it
1153 :returns: (Obj, remaining data)
1157 elif _ctx_immutable:
1159 tlv = memoryview(data)
1160 if self._expl is None:
1161 result = self._decode(
1164 decode_path=decode_path,
1173 t, tlen, lv = tag_strip(tlv)
1174 except DecodeError as err:
1175 raise err.__class__(
1177 klass=self.__class__,
1178 decode_path=decode_path,
1183 klass=self.__class__,
1184 decode_path=decode_path,
1188 l, llen, v = len_decode(lv)
1189 except LenIndefForm as err:
1190 if not ctx.get("bered", False):
1191 raise err.__class__(
1193 klass=self.__class__,
1194 decode_path=decode_path,
1198 offset += tlen + llen
1199 result = self._decode(
1202 decode_path=decode_path,
1206 if tag_only: # pragma: no cover
1209 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1210 if eoc_expected.tobytes() != EOC:
1213 klass=self.__class__,
1214 decode_path=decode_path,
1218 obj.expl_lenindef = True
1219 except DecodeError as err:
1220 raise err.__class__(
1222 klass=self.__class__,
1223 decode_path=decode_path,
1228 raise NotEnoughData(
1229 "encoded length is longer than data",
1230 klass=self.__class__,
1231 decode_path=decode_path,
1234 result = self._decode(
1236 offset=offset + tlen + llen,
1237 decode_path=decode_path,
1241 if tag_only: # pragma: no cover
1244 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1246 "explicit tag out-of-bound, longer than data",
1247 klass=self.__class__,
1248 decode_path=decode_path,
1251 return obj, (tail if leavemm else tail.tobytes())
1255 return self._expl is not None
1262 def expl_tlen(self):
1263 return len(self._expl)
1266 def expl_llen(self):
1267 if self.expl_lenindef:
1269 return len(len_encode(self.tlvlen))
1272 def expl_offset(self):
1273 return self.offset - self.expl_tlen - self.expl_llen
1276 def expl_vlen(self):
1280 def expl_tlvlen(self):
1281 return self.expl_tlen + self.expl_llen + self.expl_vlen
1284 def fulloffset(self):
1285 return self.expl_offset if self.expled else self.offset
1289 return self.expl_tlvlen if self.expled else self.tlvlen
1291 def pps_lenindef(self, decode_path):
1292 if self.lenindef and not (
1293 getattr(self, "defined", None) is not None and
1294 self.defined[1].lenindef
1297 asn1_type_name="EOC",
1299 decode_path=decode_path,
1301 self.offset + self.tlvlen -
1302 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1310 if self.expl_lenindef:
1312 asn1_type_name="EOC",
1313 obj_name="EXPLICIT",
1314 decode_path=decode_path,
1315 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1324 class DecodePathDefBy(object):
1325 """DEFINED BY representation inside decode path
1327 __slots__ = ("defined_by",)
1329 def __init__(self, defined_by):
1330 self.defined_by = defined_by
1332 def __ne__(self, their):
1333 return not(self == their)
1335 def __eq__(self, their):
1336 if not isinstance(their, self.__class__):
1338 return self.defined_by == their.defined_by
1341 return "DEFINED BY " + str(self.defined_by)
1344 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1347 ########################################################################
1349 ########################################################################
1351 PP = namedtuple("PP", (
1379 asn1_type_name="unknown",
1396 expl_lenindef=False,
1427 def _colourize(what, colour, with_colours, attrs=("bold",)):
1428 return colored(what, colour, attrs=attrs) if with_colours else what
1431 def colonize_hex(hexed):
1432 """Separate hexadecimal string with colons
1434 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1443 with_decode_path=False,
1444 decode_path_len_decrease=0,
1451 " " if pp.expl_offset is None else
1452 ("-%d" % (pp.offset - pp.expl_offset))
1454 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1456 col = _colourize(col, "red", with_colours, ())
1457 col += _colourize("B", "red", with_colours) if pp.bered else " "
1459 col = "[%d,%d,%4d]%s" % (
1463 LENINDEF_PP_CHAR if pp.lenindef else " "
1465 col = _colourize(col, "green", with_colours, ())
1467 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1468 if decode_path_len > 0:
1469 cols.append(" ." * decode_path_len)
1470 ent = pp.decode_path[-1]
1471 if isinstance(ent, DecodePathDefBy):
1472 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1473 value = str(ent.defined_by)
1476 len(oid_maps) > 0 and
1477 ent.defined_by.asn1_type_name ==
1478 ObjectIdentifier.asn1_type_name
1480 for oid_map in oid_maps:
1481 oid_name = oid_map.get(value)
1482 if oid_name is not None:
1483 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1485 if oid_name is None:
1486 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1488 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1489 if pp.expl is not None:
1490 klass, _, num = pp.expl
1491 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1492 cols.append(_colourize(col, "blue", with_colours))
1493 if pp.impl is not None:
1494 klass, _, num = pp.impl
1495 col = "[%s%d]" % (TagClassReprs[klass], num)
1496 cols.append(_colourize(col, "blue", with_colours))
1497 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1498 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1500 cols.append(_colourize("BER", "red", with_colours))
1501 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1502 if pp.value is not None:
1504 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1506 len(oid_maps) > 0 and
1507 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1509 for oid_map in oid_maps:
1510 oid_name = oid_map.get(value)
1511 if oid_name is not None:
1512 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1514 if pp.asn1_type_name == Integer.asn1_type_name:
1515 hex_repr = hex(int(pp.obj._value))[2:].upper()
1516 if len(hex_repr) % 2 != 0:
1517 hex_repr = "0" + hex_repr
1518 cols.append(_colourize(
1519 "(%s)" % colonize_hex(hex_repr),
1524 if isinstance(pp.blob, binary_type):
1525 cols.append(hexenc(pp.blob))
1526 elif isinstance(pp.blob, tuple):
1527 cols.append(", ".join(pp.blob))
1529 cols.append(_colourize("OPTIONAL", "red", with_colours))
1531 cols.append(_colourize("DEFAULT", "red", with_colours))
1532 if with_decode_path:
1533 cols.append(_colourize(
1534 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1538 return " ".join(cols)
1541 def pp_console_blob(pp, decode_path_len_decrease=0):
1542 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1543 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1544 if decode_path_len > 0:
1545 cols.append(" ." * (decode_path_len + 1))
1546 if isinstance(pp.blob, binary_type):
1547 blob = hexenc(pp.blob).upper()
1548 for i in six_xrange(0, len(blob), 32):
1549 chunk = blob[i:i + 32]
1550 yield " ".join(cols + [colonize_hex(chunk)])
1551 elif isinstance(pp.blob, tuple):
1552 yield " ".join(cols + [", ".join(pp.blob)])
1560 with_decode_path=False,
1561 decode_path_only=(),
1563 """Pretty print object
1565 :param Obj obj: object you want to pretty print
1566 :param oid_maps: list of ``OID <-> humand readable string`` dictionary.
1567 When OID from it is met, then its humand readable form
1569 :param big_blobs: if large binary objects are met (like OctetString
1570 values), do we need to print them too, on separate
1572 :param with_colours: colourize output, if ``termcolor`` library
1574 :param with_decode_path: print decode path
1575 :param decode_path_only: print only that specified decode path
1577 def _pprint_pps(pps):
1579 if hasattr(pp, "_fields"):
1581 decode_path_only != () and
1583 str(p) for p in pp.decode_path[:len(decode_path_only)]
1584 ) != decode_path_only
1588 yield pp_console_row(
1593 with_colours=with_colours,
1594 with_decode_path=with_decode_path,
1595 decode_path_len_decrease=len(decode_path_only),
1597 for row in pp_console_blob(
1599 decode_path_len_decrease=len(decode_path_only),
1603 yield pp_console_row(
1608 with_colours=with_colours,
1609 with_decode_path=with_decode_path,
1610 decode_path_len_decrease=len(decode_path_only),
1613 for row in _pprint_pps(pp):
1615 return "\n".join(_pprint_pps(obj.pps()))
1618 ########################################################################
1619 # ASN.1 primitive types
1620 ########################################################################
1623 """``BOOLEAN`` boolean type
1625 >>> b = Boolean(True)
1627 >>> b == Boolean(True)
1633 tag_default = tag_encode(1)
1634 asn1_type_name = "BOOLEAN"
1646 :param value: set the value. Either boolean type, or
1647 :py:class:`pyderasn.Boolean` object
1648 :param bytes impl: override default tag with ``IMPLICIT`` one
1649 :param bytes expl: override default tag with ``EXPLICIT`` one
1650 :param default: set default value. Type same as in ``value``
1651 :param bool optional: is object ``OPTIONAL`` in sequence
1653 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1654 self._value = None if value is None else self._value_sanitize(value)
1655 if default is not None:
1656 default = self._value_sanitize(default)
1657 self.default = self.__class__(
1663 self._value = default
1665 def _value_sanitize(self, value):
1666 if isinstance(value, bool):
1668 if issubclass(value.__class__, Boolean):
1670 raise InvalidValueType((self.__class__, bool))
1674 return self._value is not None
1677 obj = self.__class__()
1678 obj._value = self._value
1680 obj._expl = self._expl
1681 obj.default = self.default
1682 obj.optional = self.optional
1683 obj.offset = self.offset
1684 obj.llen = self.llen
1685 obj.vlen = self.vlen
1686 obj.expl_lenindef = self.expl_lenindef
1687 obj.lenindef = self.lenindef
1688 obj.ber_encoded = self.ber_encoded
1691 def __nonzero__(self):
1692 self._assert_ready()
1696 self._assert_ready()
1699 def __eq__(self, their):
1700 if isinstance(their, bool):
1701 return self._value == their
1702 if not issubclass(their.__class__, Boolean):
1705 self._value == their._value and
1706 self.tag == their.tag and
1707 self._expl == their._expl
1718 return self.__class__(
1720 impl=self.tag if impl is None else impl,
1721 expl=self._expl if expl is None else expl,
1722 default=self.default if default is None else default,
1723 optional=self.optional if optional is None else optional,
1727 self._assert_ready()
1731 (b"\xFF" if self._value else b"\x00"),
1734 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1736 t, _, lv = tag_strip(tlv)
1737 except DecodeError as err:
1738 raise err.__class__(
1740 klass=self.__class__,
1741 decode_path=decode_path,
1746 klass=self.__class__,
1747 decode_path=decode_path,
1753 l, _, v = len_decode(lv)
1754 except DecodeError as err:
1755 raise err.__class__(
1757 klass=self.__class__,
1758 decode_path=decode_path,
1762 raise InvalidLength(
1763 "Boolean's length must be equal to 1",
1764 klass=self.__class__,
1765 decode_path=decode_path,
1769 raise NotEnoughData(
1770 "encoded length is longer than data",
1771 klass=self.__class__,
1772 decode_path=decode_path,
1775 first_octet = byte2int(v)
1777 if first_octet == 0:
1779 elif first_octet == 0xFF:
1781 elif ctx.get("bered", False):
1786 "unacceptable Boolean value",
1787 klass=self.__class__,
1788 decode_path=decode_path,
1791 obj = self.__class__(
1795 default=self.default,
1796 optional=self.optional,
1797 _decoded=(offset, 1, 1),
1799 obj.ber_encoded = ber_encoded
1803 return pp_console_row(next(self.pps()))
1805 def pps(self, decode_path=()):
1808 asn1_type_name=self.asn1_type_name,
1809 obj_name=self.__class__.__name__,
1810 decode_path=decode_path,
1811 value=str(self._value) if self.ready else None,
1812 optional=self.optional,
1813 default=self == self.default,
1814 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1815 expl=None if self._expl is None else tag_decode(self._expl),
1820 expl_offset=self.expl_offset if self.expled else None,
1821 expl_tlen=self.expl_tlen if self.expled else None,
1822 expl_llen=self.expl_llen if self.expled else None,
1823 expl_vlen=self.expl_vlen if self.expled else None,
1824 expl_lenindef=self.expl_lenindef,
1825 ber_encoded=self.ber_encoded,
1828 for pp in self.pps_lenindef(decode_path):
1833 """``INTEGER`` integer type
1835 >>> b = Integer(-123)
1837 >>> b == Integer(-123)
1842 >>> Integer(2, bounds=(1, 3))
1844 >>> Integer(5, bounds=(1, 3))
1845 Traceback (most recent call last):
1846 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1850 class Version(Integer):
1857 >>> v = Version("v1")
1864 {'v3': 2, 'v1': 0, 'v2': 1}
1866 __slots__ = ("specs", "_bound_min", "_bound_max")
1867 tag_default = tag_encode(2)
1868 asn1_type_name = "INTEGER"
1882 :param value: set the value. Either integer type, named value
1883 (if ``schema`` is specified in the class), or
1884 :py:class:`pyderasn.Integer` object
1885 :param bounds: set ``(MIN, MAX)`` value constraint.
1886 (-inf, +inf) by default
1887 :param bytes impl: override default tag with ``IMPLICIT`` one
1888 :param bytes expl: override default tag with ``EXPLICIT`` one
1889 :param default: set default value. Type same as in ``value``
1890 :param bool optional: is object ``OPTIONAL`` in sequence
1892 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
1894 specs = getattr(self, "schema", {}) if _specs is None else _specs
1895 self.specs = specs if isinstance(specs, dict) else dict(specs)
1896 self._bound_min, self._bound_max = getattr(
1899 (float("-inf"), float("+inf")),
1900 ) if bounds is None else bounds
1901 if value is not None:
1902 self._value = self._value_sanitize(value)
1903 if default is not None:
1904 default = self._value_sanitize(default)
1905 self.default = self.__class__(
1911 if self._value is None:
1912 self._value = default
1914 def _value_sanitize(self, value):
1915 if isinstance(value, integer_types):
1917 elif issubclass(value.__class__, Integer):
1918 value = value._value
1919 elif isinstance(value, str):
1920 value = self.specs.get(value)
1922 raise ObjUnknown("integer value: %s" % value)
1924 raise InvalidValueType((self.__class__, int, str))
1925 if not self._bound_min <= value <= self._bound_max:
1926 raise BoundsError(self._bound_min, value, self._bound_max)
1931 return self._value is not None
1934 obj = self.__class__(_specs=self.specs)
1935 obj._value = self._value
1936 obj._bound_min = self._bound_min
1937 obj._bound_max = self._bound_max
1939 obj._expl = self._expl
1940 obj.default = self.default
1941 obj.optional = self.optional
1942 obj.offset = self.offset
1943 obj.llen = self.llen
1944 obj.vlen = self.vlen
1945 obj.expl_lenindef = self.expl_lenindef
1946 obj.lenindef = self.lenindef
1947 obj.ber_encoded = self.ber_encoded
1951 self._assert_ready()
1952 return int(self._value)
1955 self._assert_ready()
1958 bytes(self._expl or b"") +
1959 str(self._value).encode("ascii"),
1962 def __eq__(self, their):
1963 if isinstance(their, integer_types):
1964 return self._value == their
1965 if not issubclass(their.__class__, Integer):
1968 self._value == their._value and
1969 self.tag == their.tag and
1970 self._expl == their._expl
1973 def __lt__(self, their):
1974 return self._value < their._value
1978 for name, value in iteritems(self.specs):
1979 if value == self._value:
1991 return self.__class__(
1994 (self._bound_min, self._bound_max)
1995 if bounds is None else bounds
1997 impl=self.tag if impl is None else impl,
1998 expl=self._expl if expl is None else expl,
1999 default=self.default if default is None else default,
2000 optional=self.optional if optional is None else optional,
2005 self._assert_ready()
2009 octets = bytearray([0])
2013 octets = bytearray()
2015 octets.append((value & 0xFF) ^ 0xFF)
2017 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2020 octets = bytearray()
2022 octets.append(value & 0xFF)
2024 if octets[-1] & 0x80 > 0:
2027 octets = bytes(octets)
2029 bytes_len = ceil(value.bit_length() / 8) or 1
2032 octets = value.to_bytes(
2037 except OverflowError:
2041 return b"".join((self.tag, len_encode(len(octets)), octets))
2043 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2045 t, _, lv = tag_strip(tlv)
2046 except DecodeError as err:
2047 raise err.__class__(
2049 klass=self.__class__,
2050 decode_path=decode_path,
2055 klass=self.__class__,
2056 decode_path=decode_path,
2062 l, llen, v = len_decode(lv)
2063 except DecodeError as err:
2064 raise err.__class__(
2066 klass=self.__class__,
2067 decode_path=decode_path,
2071 raise NotEnoughData(
2072 "encoded length is longer than data",
2073 klass=self.__class__,
2074 decode_path=decode_path,
2078 raise NotEnoughData(
2080 klass=self.__class__,
2081 decode_path=decode_path,
2084 v, tail = v[:l], v[l:]
2085 first_octet = byte2int(v)
2087 second_octet = byte2int(v[1:])
2089 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2090 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2093 "non normalized integer",
2094 klass=self.__class__,
2095 decode_path=decode_path,
2100 if first_octet & 0x80 > 0:
2101 octets = bytearray()
2102 for octet in bytearray(v):
2103 octets.append(octet ^ 0xFF)
2104 for octet in octets:
2105 value = (value << 8) | octet
2109 for octet in bytearray(v):
2110 value = (value << 8) | octet
2112 value = int.from_bytes(v, byteorder="big", signed=True)
2114 obj = self.__class__(
2116 bounds=(self._bound_min, self._bound_max),
2119 default=self.default,
2120 optional=self.optional,
2122 _decoded=(offset, llen, l),
2124 except BoundsError as err:
2127 klass=self.__class__,
2128 decode_path=decode_path,
2134 return pp_console_row(next(self.pps()))
2136 def pps(self, decode_path=()):
2139 asn1_type_name=self.asn1_type_name,
2140 obj_name=self.__class__.__name__,
2141 decode_path=decode_path,
2142 value=(self.named or str(self._value)) if self.ready else None,
2143 optional=self.optional,
2144 default=self == self.default,
2145 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2146 expl=None if self._expl is None else tag_decode(self._expl),
2151 expl_offset=self.expl_offset if self.expled else None,
2152 expl_tlen=self.expl_tlen if self.expled else None,
2153 expl_llen=self.expl_llen if self.expled else None,
2154 expl_vlen=self.expl_vlen if self.expled else None,
2155 expl_lenindef=self.expl_lenindef,
2158 for pp in self.pps_lenindef(decode_path):
2162 SET01 = frozenset(("0", "1"))
2165 class BitString(Obj):
2166 """``BIT STRING`` bit string type
2168 >>> BitString(b"hello world")
2169 BIT STRING 88 bits 68656c6c6f20776f726c64
2172 >>> b == b"hello world"
2177 >>> BitString("'0A3B5F291CD'H")
2178 BIT STRING 44 bits 0a3b5f291cd0
2179 >>> b = BitString("'010110000000'B")
2180 BIT STRING 12 bits 5800
2183 >>> b[0], b[1], b[2], b[3]
2184 (False, True, False, True)
2188 [False, True, False, True, True, False, False, False, False, False, False, False]
2192 class KeyUsage(BitString):
2194 ("digitalSignature", 0),
2195 ("nonRepudiation", 1),
2196 ("keyEncipherment", 2),
2199 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2200 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2202 ['nonRepudiation', 'keyEncipherment']
2204 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2208 Pay attention that BIT STRING can be encoded both in primitive
2209 and constructed forms. Decoder always checks constructed form tag
2210 additionally to specified primitive one. If BER decoding is
2211 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2212 of DER restrictions.
2214 __slots__ = ("tag_constructed", "specs", "defined")
2215 tag_default = tag_encode(3)
2216 asn1_type_name = "BIT STRING"
2229 :param value: set the value. Either binary type, tuple of named
2230 values (if ``schema`` is specified in the class),
2231 string in ``'XXX...'B`` form, or
2232 :py:class:`pyderasn.BitString` object
2233 :param bytes impl: override default tag with ``IMPLICIT`` one
2234 :param bytes expl: override default tag with ``EXPLICIT`` one
2235 :param default: set default value. Type same as in ``value``
2236 :param bool optional: is object ``OPTIONAL`` in sequence
2238 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2239 specs = getattr(self, "schema", {}) if _specs is None else _specs
2240 self.specs = specs if isinstance(specs, dict) else dict(specs)
2241 self._value = None if value is None else self._value_sanitize(value)
2242 if default is not None:
2243 default = self._value_sanitize(default)
2244 self.default = self.__class__(
2250 self._value = default
2252 tag_klass, _, tag_num = tag_decode(self.tag)
2253 self.tag_constructed = tag_encode(
2255 form=TagFormConstructed,
2259 def _bits2octets(self, bits):
2260 if len(self.specs) > 0:
2261 bits = bits.rstrip("0")
2263 bits += "0" * ((8 - (bit_len % 8)) % 8)
2264 octets = bytearray(len(bits) // 8)
2265 for i in six_xrange(len(octets)):
2266 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2267 return bit_len, bytes(octets)
2269 def _value_sanitize(self, value):
2270 if isinstance(value, (string_types, binary_type)):
2272 isinstance(value, string_types) and
2273 value.startswith("'")
2275 if value.endswith("'B"):
2277 if not frozenset(value) <= SET01:
2278 raise ValueError("B's coding contains unacceptable chars")
2279 return self._bits2octets(value)
2280 elif value.endswith("'H"):
2284 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2286 if isinstance(value, binary_type):
2287 return (len(value) * 8, value)
2289 raise InvalidValueType((self.__class__, string_types, binary_type))
2290 if isinstance(value, tuple):
2293 isinstance(value[0], integer_types) and
2294 isinstance(value[1], binary_type)
2299 bit = self.specs.get(name)
2301 raise ObjUnknown("BitString value: %s" % name)
2304 return self._bits2octets("")
2305 bits = frozenset(bits)
2306 return self._bits2octets("".join(
2307 ("1" if bit in bits else "0")
2308 for bit in six_xrange(max(bits) + 1)
2310 if issubclass(value.__class__, BitString):
2312 raise InvalidValueType((self.__class__, binary_type, string_types))
2316 return self._value is not None
2319 obj = self.__class__(_specs=self.specs)
2321 if value is not None:
2322 value = (value[0], value[1])
2325 obj._expl = self._expl
2326 obj.default = self.default
2327 obj.optional = self.optional
2328 obj.offset = self.offset
2329 obj.llen = self.llen
2330 obj.vlen = self.vlen
2331 obj.expl_lenindef = self.expl_lenindef
2332 obj.lenindef = self.lenindef
2333 obj.ber_encoded = self.ber_encoded
2337 self._assert_ready()
2338 for i in six_xrange(self._value[0]):
2343 self._assert_ready()
2344 return self._value[0]
2346 def __bytes__(self):
2347 self._assert_ready()
2348 return self._value[1]
2350 def __eq__(self, their):
2351 if isinstance(their, bytes):
2352 return self._value[1] == their
2353 if not issubclass(their.__class__, BitString):
2356 self._value == their._value and
2357 self.tag == their.tag and
2358 self._expl == their._expl
2363 return [name for name, bit in iteritems(self.specs) if self[bit]]
2373 return self.__class__(
2375 impl=self.tag if impl is None else impl,
2376 expl=self._expl if expl is None else expl,
2377 default=self.default if default is None else default,
2378 optional=self.optional if optional is None else optional,
2382 def __getitem__(self, key):
2383 if isinstance(key, int):
2384 bit_len, octets = self._value
2388 byte2int(memoryview(octets)[key // 8:]) >>
2391 if isinstance(key, string_types):
2392 value = self.specs.get(key)
2394 raise ObjUnknown("BitString value: %s" % key)
2396 raise InvalidValueType((int, str))
2399 self._assert_ready()
2400 bit_len, octets = self._value
2403 len_encode(len(octets) + 1),
2404 int2byte((8 - bit_len % 8) % 8),
2408 def _decode_chunk(self, lv, offset, decode_path, ctx):
2410 l, llen, v = len_decode(lv)
2411 except DecodeError as err:
2412 raise err.__class__(
2414 klass=self.__class__,
2415 decode_path=decode_path,
2419 raise NotEnoughData(
2420 "encoded length is longer than data",
2421 klass=self.__class__,
2422 decode_path=decode_path,
2426 raise NotEnoughData(
2428 klass=self.__class__,
2429 decode_path=decode_path,
2432 pad_size = byte2int(v)
2433 if l == 1 and pad_size != 0:
2435 "invalid empty value",
2436 klass=self.__class__,
2437 decode_path=decode_path,
2443 klass=self.__class__,
2444 decode_path=decode_path,
2447 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2450 klass=self.__class__,
2451 decode_path=decode_path,
2454 v, tail = v[:l], v[l:]
2455 obj = self.__class__(
2456 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2459 default=self.default,
2460 optional=self.optional,
2462 _decoded=(offset, llen, l),
2466 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2468 t, tlen, lv = tag_strip(tlv)
2469 except DecodeError as err:
2470 raise err.__class__(
2472 klass=self.__class__,
2473 decode_path=decode_path,
2477 if tag_only: # pragma: no cover
2479 return self._decode_chunk(lv, offset, decode_path, ctx)
2480 if t == self.tag_constructed:
2481 if not ctx.get("bered", False):
2483 "unallowed BER constructed encoding",
2484 klass=self.__class__,
2485 decode_path=decode_path,
2488 if tag_only: # pragma: no cover
2492 l, llen, v = len_decode(lv)
2493 except LenIndefForm:
2494 llen, l, v = 1, 0, lv[1:]
2496 except DecodeError as err:
2497 raise err.__class__(
2499 klass=self.__class__,
2500 decode_path=decode_path,
2504 raise NotEnoughData(
2505 "encoded length is longer than data",
2506 klass=self.__class__,
2507 decode_path=decode_path,
2510 if not lenindef and l == 0:
2511 raise NotEnoughData(
2513 klass=self.__class__,
2514 decode_path=decode_path,
2518 sub_offset = offset + tlen + llen
2522 if v[:EOC_LEN].tobytes() == EOC:
2529 "chunk out of bounds",
2530 klass=self.__class__,
2531 decode_path=decode_path + (str(len(chunks) - 1),),
2532 offset=chunks[-1].offset,
2534 sub_decode_path = decode_path + (str(len(chunks)),)
2536 chunk, v_tail = BitString().decode(
2539 decode_path=sub_decode_path,
2542 _ctx_immutable=False,
2546 "expected BitString encoded chunk",
2547 klass=self.__class__,
2548 decode_path=sub_decode_path,
2551 chunks.append(chunk)
2552 sub_offset += chunk.tlvlen
2553 vlen += chunk.tlvlen
2555 if len(chunks) == 0:
2558 klass=self.__class__,
2559 decode_path=decode_path,
2564 for chunk_i, chunk in enumerate(chunks[:-1]):
2565 if chunk.bit_len % 8 != 0:
2567 "BitString chunk is not multiple of 8 bits",
2568 klass=self.__class__,
2569 decode_path=decode_path + (str(chunk_i),),
2570 offset=chunk.offset,
2572 values.append(bytes(chunk))
2573 bit_len += chunk.bit_len
2574 chunk_last = chunks[-1]
2575 values.append(bytes(chunk_last))
2576 bit_len += chunk_last.bit_len
2577 obj = self.__class__(
2578 value=(bit_len, b"".join(values)),
2581 default=self.default,
2582 optional=self.optional,
2584 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2586 obj.lenindef = lenindef
2587 obj.ber_encoded = True
2588 return obj, (v[EOC_LEN:] if lenindef else v)
2590 klass=self.__class__,
2591 decode_path=decode_path,
2596 return pp_console_row(next(self.pps()))
2598 def pps(self, decode_path=()):
2602 bit_len, blob = self._value
2603 value = "%d bits" % bit_len
2604 if len(self.specs) > 0:
2605 blob = tuple(self.named)
2608 asn1_type_name=self.asn1_type_name,
2609 obj_name=self.__class__.__name__,
2610 decode_path=decode_path,
2613 optional=self.optional,
2614 default=self == self.default,
2615 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2616 expl=None if self._expl is None else tag_decode(self._expl),
2621 expl_offset=self.expl_offset if self.expled else None,
2622 expl_tlen=self.expl_tlen if self.expled else None,
2623 expl_llen=self.expl_llen if self.expled else None,
2624 expl_vlen=self.expl_vlen if self.expled else None,
2625 expl_lenindef=self.expl_lenindef,
2626 lenindef=self.lenindef,
2627 ber_encoded=self.ber_encoded,
2630 defined_by, defined = self.defined or (None, None)
2631 if defined_by is not None:
2633 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2635 for pp in self.pps_lenindef(decode_path):
2639 class OctetString(Obj):
2640 """``OCTET STRING`` binary string type
2642 >>> s = OctetString(b"hello world")
2643 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2644 >>> s == OctetString(b"hello world")
2649 >>> OctetString(b"hello", bounds=(4, 4))
2650 Traceback (most recent call last):
2651 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2652 >>> OctetString(b"hell", bounds=(4, 4))
2653 OCTET STRING 4 bytes 68656c6c
2657 Pay attention that OCTET STRING can be encoded both in primitive
2658 and constructed forms. Decoder always checks constructed form tag
2659 additionally to specified primitive one. If BER decoding is
2660 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2661 of DER restrictions.
2663 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2664 tag_default = tag_encode(4)
2665 asn1_type_name = "OCTET STRING"
2678 :param value: set the value. Either binary type, or
2679 :py:class:`pyderasn.OctetString` object
2680 :param bounds: set ``(MIN, MAX)`` value size constraint.
2681 (-inf, +inf) by default
2682 :param bytes impl: override default tag with ``IMPLICIT`` one
2683 :param bytes expl: override default tag with ``EXPLICIT`` one
2684 :param default: set default value. Type same as in ``value``
2685 :param bool optional: is object ``OPTIONAL`` in sequence
2687 super(OctetString, self).__init__(
2695 self._bound_min, self._bound_max = getattr(
2699 ) if bounds is None else bounds
2700 if value is not None:
2701 self._value = self._value_sanitize(value)
2702 if default is not None:
2703 default = self._value_sanitize(default)
2704 self.default = self.__class__(
2709 if self._value is None:
2710 self._value = default
2712 tag_klass, _, tag_num = tag_decode(self.tag)
2713 self.tag_constructed = tag_encode(
2715 form=TagFormConstructed,
2719 def _value_sanitize(self, value):
2720 if isinstance(value, binary_type):
2722 elif issubclass(value.__class__, OctetString):
2723 value = value._value
2725 raise InvalidValueType((self.__class__, bytes))
2726 if not self._bound_min <= len(value) <= self._bound_max:
2727 raise BoundsError(self._bound_min, len(value), self._bound_max)
2732 return self._value is not None
2735 obj = self.__class__()
2736 obj._value = self._value
2737 obj._bound_min = self._bound_min
2738 obj._bound_max = self._bound_max
2740 obj._expl = self._expl
2741 obj.default = self.default
2742 obj.optional = self.optional
2743 obj.offset = self.offset
2744 obj.llen = self.llen
2745 obj.vlen = self.vlen
2746 obj.expl_lenindef = self.expl_lenindef
2747 obj.lenindef = self.lenindef
2748 obj.ber_encoded = self.ber_encoded
2751 def __bytes__(self):
2752 self._assert_ready()
2755 def __eq__(self, their):
2756 if isinstance(their, binary_type):
2757 return self._value == their
2758 if not issubclass(their.__class__, OctetString):
2761 self._value == their._value and
2762 self.tag == their.tag and
2763 self._expl == their._expl
2766 def __lt__(self, their):
2767 return self._value < their._value
2778 return self.__class__(
2781 (self._bound_min, self._bound_max)
2782 if bounds is None else bounds
2784 impl=self.tag if impl is None else impl,
2785 expl=self._expl if expl is None else expl,
2786 default=self.default if default is None else default,
2787 optional=self.optional if optional is None else optional,
2791 self._assert_ready()
2794 len_encode(len(self._value)),
2798 def _decode_chunk(self, lv, offset, decode_path, ctx):
2800 l, llen, v = len_decode(lv)
2801 except DecodeError as err:
2802 raise err.__class__(
2804 klass=self.__class__,
2805 decode_path=decode_path,
2809 raise NotEnoughData(
2810 "encoded length is longer than data",
2811 klass=self.__class__,
2812 decode_path=decode_path,
2815 v, tail = v[:l], v[l:]
2817 obj = self.__class__(
2819 bounds=(self._bound_min, self._bound_max),
2822 default=self.default,
2823 optional=self.optional,
2824 _decoded=(offset, llen, l),
2826 except DecodeError as err:
2829 klass=self.__class__,
2830 decode_path=decode_path,
2833 except BoundsError as err:
2836 klass=self.__class__,
2837 decode_path=decode_path,
2842 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2844 t, tlen, lv = tag_strip(tlv)
2845 except DecodeError as err:
2846 raise err.__class__(
2848 klass=self.__class__,
2849 decode_path=decode_path,
2855 return self._decode_chunk(lv, offset, decode_path, ctx)
2856 if t == self.tag_constructed:
2857 if not ctx.get("bered", False):
2859 "unallowed BER constructed encoding",
2860 klass=self.__class__,
2861 decode_path=decode_path,
2868 l, llen, v = len_decode(lv)
2869 except LenIndefForm:
2870 llen, l, v = 1, 0, lv[1:]
2872 except DecodeError as err:
2873 raise err.__class__(
2875 klass=self.__class__,
2876 decode_path=decode_path,
2880 raise NotEnoughData(
2881 "encoded length is longer than data",
2882 klass=self.__class__,
2883 decode_path=decode_path,
2887 sub_offset = offset + tlen + llen
2891 if v[:EOC_LEN].tobytes() == EOC:
2898 "chunk out of bounds",
2899 klass=self.__class__,
2900 decode_path=decode_path + (str(len(chunks) - 1),),
2901 offset=chunks[-1].offset,
2903 sub_decode_path = decode_path + (str(len(chunks)),)
2905 chunk, v_tail = OctetString().decode(
2908 decode_path=sub_decode_path,
2911 _ctx_immutable=False,
2915 "expected OctetString encoded chunk",
2916 klass=self.__class__,
2917 decode_path=sub_decode_path,
2920 chunks.append(chunk)
2921 sub_offset += chunk.tlvlen
2922 vlen += chunk.tlvlen
2925 obj = self.__class__(
2926 value=b"".join(bytes(chunk) for chunk in chunks),
2927 bounds=(self._bound_min, self._bound_max),
2930 default=self.default,
2931 optional=self.optional,
2932 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2934 except DecodeError as err:
2937 klass=self.__class__,
2938 decode_path=decode_path,
2941 except BoundsError as err:
2944 klass=self.__class__,
2945 decode_path=decode_path,
2948 obj.lenindef = lenindef
2949 obj.ber_encoded = True
2950 return obj, (v[EOC_LEN:] if lenindef else v)
2952 klass=self.__class__,
2953 decode_path=decode_path,
2958 return pp_console_row(next(self.pps()))
2960 def pps(self, decode_path=()):
2963 asn1_type_name=self.asn1_type_name,
2964 obj_name=self.__class__.__name__,
2965 decode_path=decode_path,
2966 value=("%d bytes" % len(self._value)) if self.ready else None,
2967 blob=self._value if self.ready else None,
2968 optional=self.optional,
2969 default=self == self.default,
2970 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2971 expl=None if self._expl is None else tag_decode(self._expl),
2976 expl_offset=self.expl_offset if self.expled else None,
2977 expl_tlen=self.expl_tlen if self.expled else None,
2978 expl_llen=self.expl_llen if self.expled else None,
2979 expl_vlen=self.expl_vlen if self.expled else None,
2980 expl_lenindef=self.expl_lenindef,
2981 lenindef=self.lenindef,
2982 ber_encoded=self.ber_encoded,
2985 defined_by, defined = self.defined or (None, None)
2986 if defined_by is not None:
2988 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2990 for pp in self.pps_lenindef(decode_path):
2995 """``NULL`` null object
3003 tag_default = tag_encode(5)
3004 asn1_type_name = "NULL"
3008 value=None, # unused, but Sequence passes it
3015 :param bytes impl: override default tag with ``IMPLICIT`` one
3016 :param bytes expl: override default tag with ``EXPLICIT`` one
3017 :param bool optional: is object ``OPTIONAL`` in sequence
3019 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3027 obj = self.__class__()
3029 obj._expl = self._expl
3030 obj.default = self.default
3031 obj.optional = self.optional
3032 obj.offset = self.offset
3033 obj.llen = self.llen
3034 obj.vlen = self.vlen
3035 obj.expl_lenindef = self.expl_lenindef
3036 obj.lenindef = self.lenindef
3037 obj.ber_encoded = self.ber_encoded
3040 def __eq__(self, their):
3041 if not issubclass(their.__class__, Null):
3044 self.tag == their.tag and
3045 self._expl == their._expl
3055 return self.__class__(
3056 impl=self.tag if impl is None else impl,
3057 expl=self._expl if expl is None else expl,
3058 optional=self.optional if optional is None else optional,
3062 return self.tag + len_encode(0)
3064 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3066 t, _, lv = tag_strip(tlv)
3067 except DecodeError as err:
3068 raise err.__class__(
3070 klass=self.__class__,
3071 decode_path=decode_path,
3076 klass=self.__class__,
3077 decode_path=decode_path,
3080 if tag_only: # pragma: no cover
3083 l, _, v = len_decode(lv)
3084 except DecodeError as err:
3085 raise err.__class__(
3087 klass=self.__class__,
3088 decode_path=decode_path,
3092 raise InvalidLength(
3093 "Null must have zero length",
3094 klass=self.__class__,
3095 decode_path=decode_path,
3098 obj = self.__class__(
3101 optional=self.optional,
3102 _decoded=(offset, 1, 0),
3107 return pp_console_row(next(self.pps()))
3109 def pps(self, decode_path=()):
3112 asn1_type_name=self.asn1_type_name,
3113 obj_name=self.__class__.__name__,
3114 decode_path=decode_path,
3115 optional=self.optional,
3116 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3117 expl=None if self._expl is None else tag_decode(self._expl),
3122 expl_offset=self.expl_offset if self.expled else None,
3123 expl_tlen=self.expl_tlen if self.expled else None,
3124 expl_llen=self.expl_llen if self.expled else None,
3125 expl_vlen=self.expl_vlen if self.expled else None,
3126 expl_lenindef=self.expl_lenindef,
3129 for pp in self.pps_lenindef(decode_path):
3133 class ObjectIdentifier(Obj):
3134 """``OBJECT IDENTIFIER`` OID type
3136 >>> oid = ObjectIdentifier((1, 2, 3))
3137 OBJECT IDENTIFIER 1.2.3
3138 >>> oid == ObjectIdentifier("1.2.3")
3144 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3145 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3147 >>> str(ObjectIdentifier((3, 1)))
3148 Traceback (most recent call last):
3149 pyderasn.InvalidOID: unacceptable first arc value
3151 __slots__ = ("defines",)
3152 tag_default = tag_encode(6)
3153 asn1_type_name = "OBJECT IDENTIFIER"
3166 :param value: set the value. Either tuples of integers,
3167 string of "."-concatenated integers, or
3168 :py:class:`pyderasn.ObjectIdentifier` object
3169 :param defines: sequence of tuples. Each tuple has two elements.
3170 First one is relative to current one decode
3171 path, aiming to the field defined by that OID.
3172 Read about relative path in
3173 :py:func:`pyderasn.abs_decode_path`. Second
3174 tuple element is ``{OID: pyderasn.Obj()}``
3175 dictionary, mapping between current OID value
3176 and structure applied to defined field.
3177 :ref:`Read about DEFINED BY <definedby>`
3178 :param bytes impl: override default tag with ``IMPLICIT`` one
3179 :param bytes expl: override default tag with ``EXPLICIT`` one
3180 :param default: set default value. Type same as in ``value``
3181 :param bool optional: is object ``OPTIONAL`` in sequence
3183 super(ObjectIdentifier, self).__init__(
3191 if value is not None:
3192 self._value = self._value_sanitize(value)
3193 if default is not None:
3194 default = self._value_sanitize(default)
3195 self.default = self.__class__(
3200 if self._value is None:
3201 self._value = default
3202 self.defines = defines
3204 def __add__(self, their):
3205 if isinstance(their, self.__class__):
3206 return self.__class__(self._value + their._value)
3207 if isinstance(their, tuple):
3208 return self.__class__(self._value + their)
3209 raise InvalidValueType((self.__class__, tuple))
3211 def _value_sanitize(self, value):
3212 if issubclass(value.__class__, ObjectIdentifier):
3214 if isinstance(value, string_types):
3216 value = tuple(int(arc) for arc in value.split("."))
3218 raise InvalidOID("unacceptable arcs values")
3219 if isinstance(value, tuple):
3221 raise InvalidOID("less than 2 arcs")
3222 first_arc = value[0]
3223 if first_arc in (0, 1):
3224 if not (0 <= value[1] <= 39):
3225 raise InvalidOID("second arc is too wide")
3226 elif first_arc == 2:
3229 raise InvalidOID("unacceptable first arc value")
3231 raise InvalidValueType((self.__class__, str, tuple))
3235 return self._value is not None
3238 obj = self.__class__()
3239 obj._value = self._value
3240 obj.defines = self.defines
3242 obj._expl = self._expl
3243 obj.default = self.default
3244 obj.optional = self.optional
3245 obj.offset = self.offset
3246 obj.llen = self.llen
3247 obj.vlen = self.vlen
3248 obj.expl_lenindef = self.expl_lenindef
3249 obj.lenindef = self.lenindef
3250 obj.ber_encoded = self.ber_encoded
3254 self._assert_ready()
3255 return iter(self._value)
3258 return ".".join(str(arc) for arc in self._value or ())
3261 self._assert_ready()
3264 bytes(self._expl or b"") +
3265 str(self._value).encode("ascii"),
3268 def __eq__(self, their):
3269 if isinstance(their, tuple):
3270 return self._value == their
3271 if not issubclass(their.__class__, ObjectIdentifier):
3274 self.tag == their.tag and
3275 self._expl == their._expl and
3276 self._value == their._value
3279 def __lt__(self, their):
3280 return self._value < their._value
3291 return self.__class__(
3293 defines=self.defines if defines is None else defines,
3294 impl=self.tag if impl is None else impl,
3295 expl=self._expl if expl is None else expl,
3296 default=self.default if default is None else default,
3297 optional=self.optional if optional is None else optional,
3301 self._assert_ready()
3303 first_value = value[1]
3304 first_arc = value[0]
3307 elif first_arc == 1:
3309 elif first_arc == 2:
3311 else: # pragma: no cover
3312 raise RuntimeError("invalid arc is stored")
3313 octets = [zero_ended_encode(first_value)]
3314 for arc in value[2:]:
3315 octets.append(zero_ended_encode(arc))
3316 v = b"".join(octets)
3317 return b"".join((self.tag, len_encode(len(v)), v))
3319 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3321 t, _, lv = tag_strip(tlv)
3322 except DecodeError as err:
3323 raise err.__class__(
3325 klass=self.__class__,
3326 decode_path=decode_path,
3331 klass=self.__class__,
3332 decode_path=decode_path,
3335 if tag_only: # pragma: no cover
3338 l, llen, v = len_decode(lv)
3339 except DecodeError as err:
3340 raise err.__class__(
3342 klass=self.__class__,
3343 decode_path=decode_path,
3347 raise NotEnoughData(
3348 "encoded length is longer than data",
3349 klass=self.__class__,
3350 decode_path=decode_path,
3354 raise NotEnoughData(
3356 klass=self.__class__,
3357 decode_path=decode_path,
3360 v, tail = v[:l], v[l:]
3367 octet = indexbytes(v, i)
3368 if i == 0 and octet == 0x80:
3369 if ctx.get("bered", False):
3372 raise DecodeError("non normalized arc encoding")
3373 arc = (arc << 7) | (octet & 0x7F)
3374 if octet & 0x80 == 0:
3382 klass=self.__class__,
3383 decode_path=decode_path,
3387 second_arc = arcs[0]
3388 if 0 <= second_arc <= 39:
3390 elif 40 <= second_arc <= 79:
3396 obj = self.__class__(
3397 value=tuple([first_arc, second_arc] + arcs[1:]),
3400 default=self.default,
3401 optional=self.optional,
3402 _decoded=(offset, llen, l),
3405 obj.ber_encoded = True
3409 return pp_console_row(next(self.pps()))
3411 def pps(self, decode_path=()):
3414 asn1_type_name=self.asn1_type_name,
3415 obj_name=self.__class__.__name__,
3416 decode_path=decode_path,
3417 value=str(self) if self.ready else None,
3418 optional=self.optional,
3419 default=self == self.default,
3420 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3421 expl=None if self._expl is None else tag_decode(self._expl),
3426 expl_offset=self.expl_offset if self.expled else None,
3427 expl_tlen=self.expl_tlen if self.expled else None,
3428 expl_llen=self.expl_llen if self.expled else None,
3429 expl_vlen=self.expl_vlen if self.expled else None,
3430 expl_lenindef=self.expl_lenindef,
3431 ber_encoded=self.ber_encoded,
3434 for pp in self.pps_lenindef(decode_path):
3438 class Enumerated(Integer):
3439 """``ENUMERATED`` integer type
3441 This type is identical to :py:class:`pyderasn.Integer`, but requires
3442 schema to be specified and does not accept values missing from it.
3445 tag_default = tag_encode(10)
3446 asn1_type_name = "ENUMERATED"
3457 bounds=None, # dummy argument, workability for Integer.decode
3459 super(Enumerated, self).__init__(
3468 if len(self.specs) == 0:
3469 raise ValueError("schema must be specified")
3471 def _value_sanitize(self, value):
3472 if isinstance(value, self.__class__):
3473 value = value._value
3474 elif isinstance(value, integer_types):
3475 for _value in itervalues(self.specs):
3480 "unknown integer value: %s" % value,
3481 klass=self.__class__,
3483 elif isinstance(value, string_types):
3484 value = self.specs.get(value)
3486 raise ObjUnknown("integer value: %s" % value)
3488 raise InvalidValueType((self.__class__, int, str))
3492 obj = self.__class__(_specs=self.specs)
3493 obj._value = self._value
3494 obj._bound_min = self._bound_min
3495 obj._bound_max = self._bound_max
3497 obj._expl = self._expl
3498 obj.default = self.default
3499 obj.optional = self.optional
3500 obj.offset = self.offset
3501 obj.llen = self.llen
3502 obj.vlen = self.vlen
3503 obj.expl_lenindef = self.expl_lenindef
3504 obj.lenindef = self.lenindef
3505 obj.ber_encoded = self.ber_encoded
3517 return self.__class__(
3519 impl=self.tag if impl is None else impl,
3520 expl=self._expl if expl is None else expl,
3521 default=self.default if default is None else default,
3522 optional=self.optional if optional is None else optional,
3527 class CommonString(OctetString):
3528 """Common class for all strings
3530 Everything resembles :py:class:`pyderasn.OctetString`, except
3531 ability to deal with unicode text strings.
3533 >>> hexenc("привет мир".encode("utf-8"))
3534 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3535 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3537 >>> s = UTF8String("привет мир")
3538 UTF8String UTF8String привет мир
3540 'привет мир'
3541 >>> hexenc(bytes(s))
3542 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3544 >>> PrintableString("привет мир")
3545 Traceback (most recent call last):
3546 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3548 >>> BMPString("ада", bounds=(2, 2))
3549 Traceback (most recent call last):
3550 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3551 >>> s = BMPString("ад", bounds=(2, 2))
3554 >>> hexenc(bytes(s))
3562 * - :py:class:`pyderasn.UTF8String`
3564 * - :py:class:`pyderasn.NumericString`
3566 * - :py:class:`pyderasn.PrintableString`
3568 * - :py:class:`pyderasn.TeletexString`
3570 * - :py:class:`pyderasn.T61String`
3572 * - :py:class:`pyderasn.VideotexString`
3574 * - :py:class:`pyderasn.IA5String`
3576 * - :py:class:`pyderasn.GraphicString`
3578 * - :py:class:`pyderasn.VisibleString`
3580 * - :py:class:`pyderasn.ISO646String`
3582 * - :py:class:`pyderasn.GeneralString`
3584 * - :py:class:`pyderasn.UniversalString`
3586 * - :py:class:`pyderasn.BMPString`
3589 __slots__ = ("encoding",)
3591 def _value_sanitize(self, value):
3593 value_decoded = None
3594 if isinstance(value, self.__class__):
3595 value_raw = value._value
3596 elif isinstance(value, text_type):
3597 value_decoded = value
3598 elif isinstance(value, binary_type):
3601 raise InvalidValueType((self.__class__, text_type, binary_type))
3604 value_decoded.encode(self.encoding)
3605 if value_raw is None else value_raw
3608 value_raw.decode(self.encoding)
3609 if value_decoded is None else value_decoded
3611 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3612 raise DecodeError(str(err))
3613 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3621 def __eq__(self, their):
3622 if isinstance(their, binary_type):
3623 return self._value == their
3624 if isinstance(their, text_type):
3625 return self._value == their.encode(self.encoding)
3626 if not isinstance(their, self.__class__):
3629 self._value == their._value and
3630 self.tag == their.tag and
3631 self._expl == their._expl
3634 def __unicode__(self):
3636 return self._value.decode(self.encoding)
3637 return text_type(self._value)
3640 return pp_console_row(next(self.pps(no_unicode=PY2)))
3642 def pps(self, decode_path=(), no_unicode=False):
3645 value = hexenc(bytes(self)) if no_unicode else self.__unicode__()
3648 asn1_type_name=self.asn1_type_name,
3649 obj_name=self.__class__.__name__,
3650 decode_path=decode_path,
3652 optional=self.optional,
3653 default=self == self.default,
3654 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3655 expl=None if self._expl is None else tag_decode(self._expl),
3660 expl_offset=self.expl_offset if self.expled else None,
3661 expl_tlen=self.expl_tlen if self.expled else None,
3662 expl_llen=self.expl_llen if self.expled else None,
3663 expl_vlen=self.expl_vlen if self.expled else None,
3664 expl_lenindef=self.expl_lenindef,
3665 ber_encoded=self.ber_encoded,
3668 for pp in self.pps_lenindef(decode_path):
3672 class UTF8String(CommonString):
3674 tag_default = tag_encode(12)
3676 asn1_type_name = "UTF8String"
3679 class AllowableCharsMixin(object):
3681 def allowable_chars(self):
3683 return self._allowable_chars
3684 return frozenset(six_unichr(c) for c in self._allowable_chars)
3687 class NumericString(AllowableCharsMixin, CommonString):
3690 Its value is properly sanitized: only ASCII digits with spaces can
3693 >>> NumericString().allowable_chars
3694 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3697 tag_default = tag_encode(18)
3699 asn1_type_name = "NumericString"
3700 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3702 def _value_sanitize(self, value):
3703 value = super(NumericString, self)._value_sanitize(value)
3704 if not frozenset(value) <= self._allowable_chars:
3705 raise DecodeError("non-numeric value")
3709 class PrintableString(AllowableCharsMixin, CommonString):
3712 Its value is properly sanitized: see X.680 41.4 table 10.
3714 >>> PrintableString().allowable_chars
3715 frozenset([' ', "'", ..., 'z'])
3718 tag_default = tag_encode(19)
3720 asn1_type_name = "PrintableString"
3721 _allowable_chars = frozenset(
3722 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
3725 def _value_sanitize(self, value):
3726 value = super(PrintableString, self)._value_sanitize(value)
3727 if not frozenset(value) <= self._allowable_chars:
3728 raise DecodeError("non-printable value")
3732 class TeletexString(CommonString):
3734 tag_default = tag_encode(20)
3736 asn1_type_name = "TeletexString"
3739 class T61String(TeletexString):
3741 asn1_type_name = "T61String"
3744 class VideotexString(CommonString):
3746 tag_default = tag_encode(21)
3747 encoding = "iso-8859-1"
3748 asn1_type_name = "VideotexString"
3751 class IA5String(CommonString):
3753 tag_default = tag_encode(22)
3755 asn1_type_name = "IA5"
3758 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
3759 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
3760 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
3763 class UTCTime(CommonString):
3764 """``UTCTime`` datetime type
3766 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3767 UTCTime UTCTime 2017-09-30T22:07:50
3773 datetime.datetime(2017, 9, 30, 22, 7, 50)
3774 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
3775 datetime.datetime(1957, 9, 30, 22, 7, 50)
3779 BER encoding is unsupported.
3782 tag_default = tag_encode(23)
3784 asn1_type_name = "UTCTime"
3794 bounds=None, # dummy argument, workability for OctetString.decode
3797 :param value: set the value. Either datetime type, or
3798 :py:class:`pyderasn.UTCTime` object
3799 :param bytes impl: override default tag with ``IMPLICIT`` one
3800 :param bytes expl: override default tag with ``EXPLICIT`` one
3801 :param default: set default value. Type same as in ``value``
3802 :param bool optional: is object ``OPTIONAL`` in sequence
3804 super(UTCTime, self).__init__(
3812 if value is not None:
3813 self._value = self._value_sanitize(value)
3814 if default is not None:
3815 default = self._value_sanitize(default)
3816 self.default = self.__class__(
3821 if self._value is None:
3822 self._value = default
3824 def _strptime(self, value):
3825 # datetime.strptime's format: %y%m%d%H%M%SZ
3826 if len(value) != LEN_YYMMDDHHMMSSZ:
3827 raise ValueError("invalid UTCTime length")
3828 if value[-1] != "Z":
3829 raise ValueError("non UTC timezone")
3831 2000 + int(value[:2]), # %y
3832 int(value[2:4]), # %m
3833 int(value[4:6]), # %d
3834 int(value[6:8]), # %H
3835 int(value[8:10]), # %M
3836 int(value[10:12]), # %S
3839 def _value_sanitize(self, value):
3840 if isinstance(value, binary_type):
3842 value_decoded = value.decode("ascii")
3843 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3844 raise DecodeError("invalid UTCTime encoding: %r" % err)
3846 self._strptime(value_decoded)
3847 except (TypeError, ValueError) as err:
3848 raise DecodeError("invalid UTCTime format: %r" % err)
3850 if isinstance(value, self.__class__):
3852 if isinstance(value, datetime):
3853 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
3854 raise InvalidValueType((self.__class__, datetime))
3856 def __eq__(self, their):
3857 if isinstance(their, binary_type):
3858 return self._value == their
3859 if isinstance(their, datetime):
3860 return self.todatetime() == their
3861 if not isinstance(their, self.__class__):
3864 self._value == their._value and
3865 self.tag == their.tag and
3866 self._expl == their._expl
3869 def todatetime(self):
3870 """Convert to datetime
3874 Pay attention that UTCTime can not hold full year, so all years
3875 having < 50 years are treated as 20xx, 19xx otherwise, according
3876 to X.509 recomendation.
3878 value = self._strptime(self._value.decode("ascii"))
3879 year = value.year % 100
3881 year=(2000 + year) if year < 50 else (1900 + year),
3885 minute=value.minute,
3886 second=value.second,
3890 return pp_console_row(next(self.pps()))
3892 def pps(self, decode_path=()):
3895 asn1_type_name=self.asn1_type_name,
3896 obj_name=self.__class__.__name__,
3897 decode_path=decode_path,
3898 value=self.todatetime().isoformat() if self.ready else None,
3899 optional=self.optional,
3900 default=self == self.default,
3901 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3902 expl=None if self._expl is None else tag_decode(self._expl),
3907 expl_offset=self.expl_offset if self.expled else None,
3908 expl_tlen=self.expl_tlen if self.expled else None,
3909 expl_llen=self.expl_llen if self.expled else None,
3910 expl_vlen=self.expl_vlen if self.expled else None,
3911 expl_lenindef=self.expl_lenindef,
3912 ber_encoded=self.ber_encoded,
3915 for pp in self.pps_lenindef(decode_path):
3919 class GeneralizedTime(UTCTime):
3920 """``GeneralizedTime`` datetime type
3922 This type is similar to :py:class:`pyderasn.UTCTime`.
3924 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3925 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
3927 '20170930220750.000123Z'
3928 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
3929 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
3933 BER encoding is unsupported.
3937 Only microsecond fractions are supported.
3938 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
3939 higher precision values.
3942 tag_default = tag_encode(24)
3943 asn1_type_name = "GeneralizedTime"
3945 def _strptime(self, value):
3947 if l == LEN_YYYYMMDDHHMMSSZ:
3948 # datetime.strptime's format: %y%m%d%H%M%SZ
3949 if value[-1] != "Z":
3950 raise ValueError("non UTC timezone")
3952 int(value[:4]), # %Y
3953 int(value[4:6]), # %m
3954 int(value[6:8]), # %d
3955 int(value[8:10]), # %H
3956 int(value[10:12]), # %M
3957 int(value[12:14]), # %S
3959 if l >= LEN_YYYYMMDDHHMMSSDMZ:
3960 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
3961 if value[-1] != "Z":
3962 raise ValueError("non UTC timezone")
3963 if value[14] != ".":
3964 raise ValueError("no fractions separator")
3967 raise ValueError("trailing zero")
3970 raise ValueError("only microsecond fractions are supported")
3971 us = int(us + ("0" * (6 - us_len)))
3973 int(value[:4]), # %Y
3974 int(value[4:6]), # %m
3975 int(value[6:8]), # %d
3976 int(value[8:10]), # %H
3977 int(value[10:12]), # %M
3978 int(value[12:14]), # %S
3982 raise ValueError("invalid GeneralizedTime length")
3984 def _value_sanitize(self, value):
3985 if isinstance(value, binary_type):
3987 value_decoded = value.decode("ascii")
3988 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3989 raise DecodeError("invalid GeneralizedTime encoding: %r" % err)
3991 self._strptime(value_decoded)
3992 except (TypeError, ValueError) as err:
3994 "invalid GeneralizedTime format: %r" % err,
3995 klass=self.__class__,
3998 if isinstance(value, self.__class__):
4000 if isinstance(value, datetime):
4001 encoded = value.strftime("%Y%m%d%H%M%S")
4002 if value.microsecond > 0:
4003 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
4004 return (encoded + "Z").encode("ascii")
4005 raise InvalidValueType((self.__class__, datetime))
4007 def todatetime(self):
4008 return self._strptime(self._value.decode("ascii"))
4011 class GraphicString(CommonString):
4013 tag_default = tag_encode(25)
4014 encoding = "iso-8859-1"
4015 asn1_type_name = "GraphicString"
4018 class VisibleString(CommonString):
4020 tag_default = tag_encode(26)
4022 asn1_type_name = "VisibleString"
4025 class ISO646String(VisibleString):
4027 asn1_type_name = "ISO646String"
4030 class GeneralString(CommonString):
4032 tag_default = tag_encode(27)
4033 encoding = "iso-8859-1"
4034 asn1_type_name = "GeneralString"
4037 class UniversalString(CommonString):
4039 tag_default = tag_encode(28)
4040 encoding = "utf-32-be"
4041 asn1_type_name = "UniversalString"
4044 class BMPString(CommonString):
4046 tag_default = tag_encode(30)
4047 encoding = "utf-16-be"
4048 asn1_type_name = "BMPString"
4052 """``CHOICE`` special type
4056 class GeneralName(Choice):
4058 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4059 ("dNSName", IA5String(impl=tag_ctxp(2))),
4062 >>> gn = GeneralName()
4064 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4065 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4066 >>> gn["dNSName"] = IA5String("bar.baz")
4067 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4068 >>> gn["rfc822Name"]
4071 [2] IA5String IA5 bar.baz
4074 >>> gn.value == gn["dNSName"]
4077 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4079 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4080 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4082 __slots__ = ("specs",)
4084 asn1_type_name = "CHOICE"
4097 :param value: set the value. Either ``(choice, value)`` tuple, or
4098 :py:class:`pyderasn.Choice` object
4099 :param bytes impl: can not be set, do **not** use it
4100 :param bytes expl: override default tag with ``EXPLICIT`` one
4101 :param default: set default value. Type same as in ``value``
4102 :param bool optional: is object ``OPTIONAL`` in sequence
4104 if impl is not None:
4105 raise ValueError("no implicit tag allowed for CHOICE")
4106 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4108 schema = getattr(self, "schema", ())
4109 if len(schema) == 0:
4110 raise ValueError("schema must be specified")
4112 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4115 if value is not None:
4116 self._value = self._value_sanitize(value)
4117 if default is not None:
4118 default_value = self._value_sanitize(default)
4119 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4120 default_obj.specs = self.specs
4121 default_obj._value = default_value
4122 self.default = default_obj
4124 self._value = default_obj.copy()._value
4126 def _value_sanitize(self, value):
4127 if isinstance(value, tuple) and len(value) == 2:
4129 spec = self.specs.get(choice)
4131 raise ObjUnknown(choice)
4132 if not isinstance(obj, spec.__class__):
4133 raise InvalidValueType((spec,))
4134 return (choice, spec(obj))
4135 if isinstance(value, self.__class__):
4137 raise InvalidValueType((self.__class__, tuple))
4141 return self._value is not None and self._value[1].ready
4145 return self.expl_lenindef or (
4146 (self._value is not None) and
4147 self._value[1].bered
4151 obj = self.__class__(schema=self.specs)
4152 obj._expl = self._expl
4153 obj.default = self.default
4154 obj.optional = self.optional
4155 obj.offset = self.offset
4156 obj.llen = self.llen
4157 obj.vlen = self.vlen
4158 obj.expl_lenindef = self.expl_lenindef
4159 obj.lenindef = self.lenindef
4160 obj.ber_encoded = self.ber_encoded
4162 if value is not None:
4163 obj._value = (value[0], value[1].copy())
4166 def __eq__(self, their):
4167 if isinstance(their, tuple) and len(their) == 2:
4168 return self._value == their
4169 if not isinstance(their, self.__class__):
4172 self.specs == their.specs and
4173 self._value == their._value
4183 return self.__class__(
4186 expl=self._expl if expl is None else expl,
4187 default=self.default if default is None else default,
4188 optional=self.optional if optional is None else optional,
4193 self._assert_ready()
4194 return self._value[0]
4198 self._assert_ready()
4199 return self._value[1]
4201 def __getitem__(self, key):
4202 if key not in self.specs:
4203 raise ObjUnknown(key)
4204 if self._value is None:
4206 choice, value = self._value
4211 def __setitem__(self, key, value):
4212 spec = self.specs.get(key)
4214 raise ObjUnknown(key)
4215 if not isinstance(value, spec.__class__):
4216 raise InvalidValueType((spec.__class__,))
4217 self._value = (key, spec(value))
4225 return self._value[1].decoded if self.ready else False
4228 self._assert_ready()
4229 return self._value[1].encode()
4231 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4232 for choice, spec in iteritems(self.specs):
4233 sub_decode_path = decode_path + (choice,)
4239 decode_path=sub_decode_path,
4242 _ctx_immutable=False,
4249 klass=self.__class__,
4250 decode_path=decode_path,
4253 if tag_only: # pragma: no cover
4255 value, tail = spec.decode(
4259 decode_path=sub_decode_path,
4261 _ctx_immutable=False,
4263 obj = self.__class__(
4266 default=self.default,
4267 optional=self.optional,
4268 _decoded=(offset, 0, value.fulllen),
4270 obj._value = (choice, value)
4274 value = pp_console_row(next(self.pps()))
4276 value = "%s[%r]" % (value, self.value)
4279 def pps(self, decode_path=()):
4282 asn1_type_name=self.asn1_type_name,
4283 obj_name=self.__class__.__name__,
4284 decode_path=decode_path,
4285 value=self.choice if self.ready else None,
4286 optional=self.optional,
4287 default=self == self.default,
4288 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4289 expl=None if self._expl is None else tag_decode(self._expl),
4294 expl_lenindef=self.expl_lenindef,
4298 yield self.value.pps(decode_path=decode_path + (self.choice,))
4299 for pp in self.pps_lenindef(decode_path):
4303 class PrimitiveTypes(Choice):
4304 """Predefined ``CHOICE`` for all generic primitive types
4306 It could be useful for general decoding of some unspecified values:
4308 >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
4309 OCTET STRING 3 bytes 666f6f
4310 >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
4314 schema = tuple((klass.__name__, klass()) for klass in (
4339 """``ANY`` special type
4341 >>> Any(Integer(-123))
4343 >>> a = Any(OctetString(b"hello world").encode())
4344 ANY 040b68656c6c6f20776f726c64
4345 >>> hexenc(bytes(a))
4346 b'0x040x0bhello world'
4348 __slots__ = ("defined",)
4349 tag_default = tag_encode(0)
4350 asn1_type_name = "ANY"
4360 :param value: set the value. Either any kind of pyderasn's
4361 **ready** object, or bytes. Pay attention that
4362 **no** validation is performed is raw binary value
4364 :param bytes expl: override default tag with ``EXPLICIT`` one
4365 :param bool optional: is object ``OPTIONAL`` in sequence
4367 super(Any, self).__init__(None, expl, None, optional, _decoded)
4368 self._value = None if value is None else self._value_sanitize(value)
4371 def _value_sanitize(self, value):
4372 if isinstance(value, binary_type):
4374 if isinstance(value, self.__class__):
4376 if isinstance(value, Obj):
4377 return value.encode()
4378 raise InvalidValueType((self.__class__, Obj, binary_type))
4382 return self._value is not None
4386 if self.expl_lenindef or self.lenindef:
4388 if self.defined is None:
4390 return self.defined[1].bered
4393 obj = self.__class__()
4394 obj._value = self._value
4396 obj._expl = self._expl
4397 obj.optional = self.optional
4398 obj.offset = self.offset
4399 obj.llen = self.llen
4400 obj.vlen = self.vlen
4401 obj.expl_lenindef = self.expl_lenindef
4402 obj.lenindef = self.lenindef
4403 obj.ber_encoded = self.ber_encoded
4406 def __eq__(self, their):
4407 if isinstance(their, binary_type):
4408 return self._value == their
4409 if issubclass(their.__class__, Any):
4410 return self._value == their._value
4419 return self.__class__(
4421 expl=self._expl if expl is None else expl,
4422 optional=self.optional if optional is None else optional,
4425 def __bytes__(self):
4426 self._assert_ready()
4434 self._assert_ready()
4437 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4439 t, tlen, lv = tag_strip(tlv)
4440 except DecodeError as err:
4441 raise err.__class__(
4443 klass=self.__class__,
4444 decode_path=decode_path,
4448 l, llen, v = len_decode(lv)
4449 except LenIndefForm as err:
4450 if not ctx.get("bered", False):
4451 raise err.__class__(
4453 klass=self.__class__,
4454 decode_path=decode_path,
4457 llen, vlen, v = 1, 0, lv[1:]
4458 sub_offset = offset + tlen + llen
4460 while v[:EOC_LEN].tobytes() != EOC:
4461 chunk, v = Any().decode(
4464 decode_path=decode_path + (str(chunk_i),),
4467 _ctx_immutable=False,
4469 vlen += chunk.tlvlen
4470 sub_offset += chunk.tlvlen
4472 tlvlen = tlen + llen + vlen + EOC_LEN
4473 obj = self.__class__(
4474 value=tlv[:tlvlen].tobytes(),
4476 optional=self.optional,
4477 _decoded=(offset, 0, tlvlen),
4481 return obj, v[EOC_LEN:]
4482 except DecodeError as err:
4483 raise err.__class__(
4485 klass=self.__class__,
4486 decode_path=decode_path,
4490 raise NotEnoughData(
4491 "encoded length is longer than data",
4492 klass=self.__class__,
4493 decode_path=decode_path,
4496 tlvlen = tlen + llen + l
4497 v, tail = tlv[:tlvlen], v[l:]
4498 obj = self.__class__(
4501 optional=self.optional,
4502 _decoded=(offset, 0, tlvlen),
4508 return pp_console_row(next(self.pps()))
4510 def pps(self, decode_path=()):
4513 asn1_type_name=self.asn1_type_name,
4514 obj_name=self.__class__.__name__,
4515 decode_path=decode_path,
4516 blob=self._value if self.ready else None,
4517 optional=self.optional,
4518 default=self == self.default,
4519 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4520 expl=None if self._expl is None else tag_decode(self._expl),
4525 expl_offset=self.expl_offset if self.expled else None,
4526 expl_tlen=self.expl_tlen if self.expled else None,
4527 expl_llen=self.expl_llen if self.expled else None,
4528 expl_vlen=self.expl_vlen if self.expled else None,
4529 expl_lenindef=self.expl_lenindef,
4530 lenindef=self.lenindef,
4533 defined_by, defined = self.defined or (None, None)
4534 if defined_by is not None:
4536 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4538 for pp in self.pps_lenindef(decode_path):
4542 ########################################################################
4543 # ASN.1 constructed types
4544 ########################################################################
4546 def get_def_by_path(defines_by_path, sub_decode_path):
4547 """Get define by decode path
4549 for path, define in defines_by_path:
4550 if len(path) != len(sub_decode_path):
4552 for p1, p2 in zip(path, sub_decode_path):
4553 if (p1 != any) and (p1 != p2):
4559 def abs_decode_path(decode_path, rel_path):
4560 """Create an absolute decode path from current and relative ones
4562 :param decode_path: current decode path, starting point. Tuple of strings
4563 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4564 If first tuple's element is "/", then treat it as
4565 an absolute path, ignoring ``decode_path`` as
4566 starting point. Also this tuple can contain ".."
4567 elements, stripping the leading element from
4570 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4571 ("foo", "bar", "baz", "whatever")
4572 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4574 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4577 if rel_path[0] == "/":
4579 if rel_path[0] == "..":
4580 return abs_decode_path(decode_path[:-1], rel_path[1:])
4581 return decode_path + rel_path
4584 class Sequence(Obj):
4585 """``SEQUENCE`` structure type
4587 You have to make specification of sequence::
4589 class Extension(Sequence):
4591 ("extnID", ObjectIdentifier()),
4592 ("critical", Boolean(default=False)),
4593 ("extnValue", OctetString()),
4596 Then, you can work with it as with dictionary.
4598 >>> ext = Extension()
4599 >>> Extension().specs
4601 ('extnID', OBJECT IDENTIFIER),
4602 ('critical', BOOLEAN False OPTIONAL DEFAULT),
4603 ('extnValue', OCTET STRING),
4605 >>> ext["extnID"] = "1.2.3"
4606 Traceback (most recent call last):
4607 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
4608 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
4610 You can determine if sequence is ready to be encoded:
4615 Traceback (most recent call last):
4616 pyderasn.ObjNotReady: object is not ready: extnValue
4617 >>> ext["extnValue"] = OctetString(b"foobar")
4621 Value you want to assign, must have the same **type** as in
4622 corresponding specification, but it can have different tags,
4623 optional/default attributes -- they will be taken from specification
4626 class TBSCertificate(Sequence):
4628 ("version", Version(expl=tag_ctxc(0), default="v1")),
4631 >>> tbs = TBSCertificate()
4632 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
4634 Assign ``None`` to remove value from sequence.
4636 You can set values in Sequence during its initialization:
4638 >>> AlgorithmIdentifier((
4639 ("algorithm", ObjectIdentifier("1.2.3")),
4640 ("parameters", Any(Null()))
4642 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
4644 You can determine if value exists/set in the sequence and take its value:
4646 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
4649 OBJECT IDENTIFIER 1.2.3
4651 But pay attention that if value has default, then it won't be (not
4652 in) in the sequence (because ``DEFAULT`` must not be encoded in
4653 DER), but you can read its value:
4655 >>> "critical" in ext, ext["critical"]
4656 (False, BOOLEAN False)
4657 >>> ext["critical"] = Boolean(True)
4658 >>> "critical" in ext, ext["critical"]
4659 (True, BOOLEAN True)
4661 All defaulted values are always optional.
4663 .. _allow_default_values_ctx:
4665 DER prohibits default value encoding and will raise an error if
4666 default value is unexpectedly met during decode.
4667 If :ref:`bered <bered_ctx>` context option is set, then no error
4668 will be raised, but ``bered`` attribute set. You can disable strict
4669 defaulted values existence validation by setting
4670 ``"allow_default_values": True`` :ref:`context <ctx>` option.
4672 Two sequences are equal if they have equal specification (schema),
4673 implicit/explicit tagging and the same values.
4675 __slots__ = ("specs",)
4676 tag_default = tag_encode(form=TagFormConstructed, num=16)
4677 asn1_type_name = "SEQUENCE"
4689 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
4691 schema = getattr(self, "schema", ())
4693 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4696 if value is not None:
4697 if issubclass(value.__class__, Sequence):
4698 self._value = value._value
4699 elif hasattr(value, "__iter__"):
4700 for seq_key, seq_value in value:
4701 self[seq_key] = seq_value
4703 raise InvalidValueType((Sequence,))
4704 if default is not None:
4705 if not issubclass(default.__class__, Sequence):
4706 raise InvalidValueType((Sequence,))
4707 default_value = default._value
4708 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4709 default_obj.specs = self.specs
4710 default_obj._value = default_value
4711 self.default = default_obj
4713 self._value = default_obj.copy()._value
4717 for name, spec in iteritems(self.specs):
4718 value = self._value.get(name)
4730 if self.expl_lenindef or self.lenindef or self.ber_encoded:
4732 return any(value.bered for value in itervalues(self._value))
4735 obj = self.__class__(schema=self.specs)
4737 obj._expl = self._expl
4738 obj.default = self.default
4739 obj.optional = self.optional
4740 obj.offset = self.offset
4741 obj.llen = self.llen
4742 obj.vlen = self.vlen
4743 obj.expl_lenindef = self.expl_lenindef
4744 obj.lenindef = self.lenindef
4745 obj.ber_encoded = self.ber_encoded
4746 obj._value = {k: v.copy() for k, v in iteritems(self._value)}
4749 def __eq__(self, their):
4750 if not isinstance(their, self.__class__):
4753 self.specs == their.specs and
4754 self.tag == their.tag and
4755 self._expl == their._expl and
4756 self._value == their._value
4767 return self.__class__(
4770 impl=self.tag if impl is None else impl,
4771 expl=self._expl if expl is None else expl,
4772 default=self.default if default is None else default,
4773 optional=self.optional if optional is None else optional,
4776 def __contains__(self, key):
4777 return key in self._value
4779 def __setitem__(self, key, value):
4780 spec = self.specs.get(key)
4782 raise ObjUnknown(key)
4784 self._value.pop(key, None)
4786 if not isinstance(value, spec.__class__):
4787 raise InvalidValueType((spec.__class__,))
4788 value = spec(value=value)
4789 if spec.default is not None and value == spec.default:
4790 self._value.pop(key, None)
4792 self._value[key] = value
4794 def __getitem__(self, key):
4795 value = self._value.get(key)
4796 if value is not None:
4798 spec = self.specs.get(key)
4800 raise ObjUnknown(key)
4801 if spec.default is not None:
4805 def _encoded_values(self):
4807 for name, spec in iteritems(self.specs):
4808 value = self._value.get(name)
4812 raise ObjNotReady(name)
4813 raws.append(value.encode())
4817 v = b"".join(self._encoded_values())
4818 return b"".join((self.tag, len_encode(len(v)), v))
4820 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4822 t, tlen, lv = tag_strip(tlv)
4823 except DecodeError as err:
4824 raise err.__class__(
4826 klass=self.__class__,
4827 decode_path=decode_path,
4832 klass=self.__class__,
4833 decode_path=decode_path,
4836 if tag_only: # pragma: no cover
4839 ctx_bered = ctx.get("bered", False)
4841 l, llen, v = len_decode(lv)
4842 except LenIndefForm as err:
4844 raise err.__class__(
4846 klass=self.__class__,
4847 decode_path=decode_path,
4850 l, llen, v = 0, 1, lv[1:]
4852 except DecodeError as err:
4853 raise err.__class__(
4855 klass=self.__class__,
4856 decode_path=decode_path,
4860 raise NotEnoughData(
4861 "encoded length is longer than data",
4862 klass=self.__class__,
4863 decode_path=decode_path,
4867 v, tail = v[:l], v[l:]
4869 sub_offset = offset + tlen + llen
4872 ctx_allow_default_values = ctx.get("allow_default_values", False)
4873 for name, spec in iteritems(self.specs):
4874 if spec.optional and (
4875 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
4879 sub_decode_path = decode_path + (name,)
4881 value, v_tail = spec.decode(
4885 decode_path=sub_decode_path,
4887 _ctx_immutable=False,
4889 except TagMismatch as err:
4890 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
4894 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
4895 if defined is not None:
4896 defined_by, defined_spec = defined
4897 if issubclass(value.__class__, SequenceOf):
4898 for i, _value in enumerate(value):
4899 sub_sub_decode_path = sub_decode_path + (
4901 DecodePathDefBy(defined_by),
4903 defined_value, defined_tail = defined_spec.decode(
4904 memoryview(bytes(_value)),
4906 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4907 if value.expled else (value.tlen + value.llen)
4910 decode_path=sub_sub_decode_path,
4912 _ctx_immutable=False,
4914 if len(defined_tail) > 0:
4917 klass=self.__class__,
4918 decode_path=sub_sub_decode_path,
4921 _value.defined = (defined_by, defined_value)
4923 defined_value, defined_tail = defined_spec.decode(
4924 memoryview(bytes(value)),
4926 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4927 if value.expled else (value.tlen + value.llen)
4930 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4932 _ctx_immutable=False,
4934 if len(defined_tail) > 0:
4937 klass=self.__class__,
4938 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4941 value.defined = (defined_by, defined_value)
4943 value_len = value.fulllen
4945 sub_offset += value_len
4947 if spec.default is not None and value == spec.default:
4948 if ctx_bered or ctx_allow_default_values:
4952 "DEFAULT value met",
4953 klass=self.__class__,
4954 decode_path=sub_decode_path,
4957 values[name] = value
4959 spec_defines = getattr(spec, "defines", ())
4960 if len(spec_defines) == 0:
4961 defines_by_path = ctx.get("defines_by_path", ())
4962 if len(defines_by_path) > 0:
4963 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
4964 if spec_defines is not None and len(spec_defines) > 0:
4965 for rel_path, schema in spec_defines:
4966 defined = schema.get(value, None)
4967 if defined is not None:
4968 ctx.setdefault("_defines", []).append((
4969 abs_decode_path(sub_decode_path[:-1], rel_path),
4973 if v[:EOC_LEN].tobytes() != EOC:
4976 klass=self.__class__,
4977 decode_path=decode_path,
4985 klass=self.__class__,
4986 decode_path=decode_path,
4989 obj = self.__class__(
4993 default=self.default,
4994 optional=self.optional,
4995 _decoded=(offset, llen, vlen),
4998 obj.lenindef = lenindef
4999 obj.ber_encoded = ber_encoded
5003 value = pp_console_row(next(self.pps()))
5005 for name in self.specs:
5006 _value = self._value.get(name)
5009 cols.append("%s: %s" % (name, repr(_value)))
5010 return "%s[%s]" % (value, "; ".join(cols))
5012 def pps(self, decode_path=()):
5015 asn1_type_name=self.asn1_type_name,
5016 obj_name=self.__class__.__name__,
5017 decode_path=decode_path,
5018 optional=self.optional,
5019 default=self == self.default,
5020 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5021 expl=None if self._expl is None else tag_decode(self._expl),
5026 expl_offset=self.expl_offset if self.expled else None,
5027 expl_tlen=self.expl_tlen if self.expled else None,
5028 expl_llen=self.expl_llen if self.expled else None,
5029 expl_vlen=self.expl_vlen if self.expled else None,
5030 expl_lenindef=self.expl_lenindef,
5031 lenindef=self.lenindef,
5032 ber_encoded=self.ber_encoded,
5035 for name in self.specs:
5036 value = self._value.get(name)
5039 yield value.pps(decode_path=decode_path + (name,))
5040 for pp in self.pps_lenindef(decode_path):
5044 class Set(Sequence):
5045 """``SET`` structure type
5047 Its usage is identical to :py:class:`pyderasn.Sequence`.
5049 .. _allow_unordered_set_ctx:
5051 DER prohibits unordered values encoding and will raise an error
5052 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5053 then no error will occure. Also you can disable strict values
5054 ordering check by setting ``"allow_unordered_set": True``
5055 :ref:`context <ctx>` option.
5058 tag_default = tag_encode(form=TagFormConstructed, num=17)
5059 asn1_type_name = "SET"
5062 raws = self._encoded_values()
5065 return b"".join((self.tag, len_encode(len(v)), v))
5067 def _specs_items(self):
5068 return iteritems(self.specs)
5070 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5072 t, tlen, lv = tag_strip(tlv)
5073 except DecodeError as err:
5074 raise err.__class__(
5076 klass=self.__class__,
5077 decode_path=decode_path,
5082 klass=self.__class__,
5083 decode_path=decode_path,
5089 ctx_bered = ctx.get("bered", False)
5091 l, llen, v = len_decode(lv)
5092 except LenIndefForm as err:
5094 raise err.__class__(
5096 klass=self.__class__,
5097 decode_path=decode_path,
5100 l, llen, v = 0, 1, lv[1:]
5102 except DecodeError as err:
5103 raise err.__class__(
5105 klass=self.__class__,
5106 decode_path=decode_path,
5110 raise NotEnoughData(
5111 "encoded length is longer than data",
5112 klass=self.__class__,
5116 v, tail = v[:l], v[l:]
5118 sub_offset = offset + tlen + llen
5121 ctx_allow_default_values = ctx.get("allow_default_values", False)
5122 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5123 value_prev = memoryview(v[:0])
5126 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5128 for name, spec in self._specs_items():
5129 sub_decode_path = decode_path + (name,)
5135 decode_path=sub_decode_path,
5138 _ctx_immutable=False,
5145 klass=self.__class__,
5146 decode_path=decode_path,
5149 value, v_tail = spec.decode(
5153 decode_path=sub_decode_path,
5155 _ctx_immutable=False,
5157 value_len = value.fulllen
5158 if value_prev.tobytes() > v[:value_len].tobytes():
5159 if ctx_bered or ctx_allow_unordered_set:
5163 "unordered " + self.asn1_type_name,
5164 klass=self.__class__,
5165 decode_path=sub_decode_path,
5168 if spec.default is None or value != spec.default:
5170 elif ctx_bered or ctx_allow_default_values:
5174 "DEFAULT value met",
5175 klass=self.__class__,
5176 decode_path=sub_decode_path,
5179 values[name] = value
5180 value_prev = v[:value_len]
5181 sub_offset += value_len
5184 obj = self.__class__(
5188 default=self.default,
5189 optional=self.optional,
5190 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5193 if v[:EOC_LEN].tobytes() != EOC:
5196 klass=self.__class__,
5197 decode_path=decode_path,
5205 "not all values are ready",
5206 klass=self.__class__,
5207 decode_path=decode_path,
5210 obj.ber_encoded = ber_encoded
5214 class SequenceOf(Obj):
5215 """``SEQUENCE OF`` sequence type
5217 For that kind of type you must specify the object it will carry on
5218 (bounds are for example here, not required)::
5220 class Ints(SequenceOf):
5225 >>> ints.append(Integer(123))
5226 >>> ints.append(Integer(234))
5228 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5229 >>> [int(i) for i in ints]
5231 >>> ints.append(Integer(345))
5232 Traceback (most recent call last):
5233 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5236 >>> ints[1] = Integer(345)
5238 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5240 Also you can initialize sequence with preinitialized values:
5242 >>> ints = Ints([Integer(123), Integer(234)])
5244 __slots__ = ("spec", "_bound_min", "_bound_max")
5245 tag_default = tag_encode(form=TagFormConstructed, num=16)
5246 asn1_type_name = "SEQUENCE OF"
5259 super(SequenceOf, self).__init__(
5267 schema = getattr(self, "schema", None)
5269 raise ValueError("schema must be specified")
5271 self._bound_min, self._bound_max = getattr(
5275 ) if bounds is None else bounds
5277 if value is not None:
5278 self._value = self._value_sanitize(value)
5279 if default is not None:
5280 default_value = self._value_sanitize(default)
5281 default_obj = self.__class__(
5286 default_obj._value = default_value
5287 self.default = default_obj
5289 self._value = default_obj.copy()._value
5291 def _value_sanitize(self, value):
5292 if issubclass(value.__class__, SequenceOf):
5293 value = value._value
5294 elif hasattr(value, "__iter__"):
5297 raise InvalidValueType((self.__class__, iter))
5298 if not self._bound_min <= len(value) <= self._bound_max:
5299 raise BoundsError(self._bound_min, len(value), self._bound_max)
5301 if not isinstance(v, self.spec.__class__):
5302 raise InvalidValueType((self.spec.__class__,))
5307 return all(v.ready for v in self._value)
5311 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5313 return any(v.bered for v in self._value)
5316 obj = self.__class__(schema=self.spec)
5317 obj._bound_min = self._bound_min
5318 obj._bound_max = self._bound_max
5320 obj._expl = self._expl
5321 obj.default = self.default
5322 obj.optional = self.optional
5323 obj.offset = self.offset
5324 obj.llen = self.llen
5325 obj.vlen = self.vlen
5326 obj.expl_lenindef = self.expl_lenindef
5327 obj.lenindef = self.lenindef
5328 obj.ber_encoded = self.ber_encoded
5329 obj._value = [v.copy() for v in self._value]
5332 def __eq__(self, their):
5333 if isinstance(their, self.__class__):
5335 self.spec == their.spec and
5336 self.tag == their.tag and
5337 self._expl == their._expl and
5338 self._value == their._value
5340 if hasattr(their, "__iter__"):
5341 return self._value == list(their)
5353 return self.__class__(
5357 (self._bound_min, self._bound_max)
5358 if bounds is None else bounds
5360 impl=self.tag if impl is None else impl,
5361 expl=self._expl if expl is None else expl,
5362 default=self.default if default is None else default,
5363 optional=self.optional if optional is None else optional,
5366 def __contains__(self, key):
5367 return key in self._value
5369 def append(self, value):
5370 if not isinstance(value, self.spec.__class__):
5371 raise InvalidValueType((self.spec.__class__,))
5372 if len(self._value) + 1 > self._bound_max:
5375 len(self._value) + 1,
5378 self._value.append(value)
5381 self._assert_ready()
5382 return iter(self._value)
5385 self._assert_ready()
5386 return len(self._value)
5388 def __setitem__(self, key, value):
5389 if not isinstance(value, self.spec.__class__):
5390 raise InvalidValueType((self.spec.__class__,))
5391 self._value[key] = self.spec(value=value)
5393 def __getitem__(self, key):
5394 return self._value[key]
5396 def _encoded_values(self):
5397 return [v.encode() for v in self._value]
5400 v = b"".join(self._encoded_values())
5401 return b"".join((self.tag, len_encode(len(v)), v))
5403 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5405 t, tlen, lv = tag_strip(tlv)
5406 except DecodeError as err:
5407 raise err.__class__(
5409 klass=self.__class__,
5410 decode_path=decode_path,
5415 klass=self.__class__,
5416 decode_path=decode_path,
5422 ctx_bered = ctx.get("bered", False)
5424 l, llen, v = len_decode(lv)
5425 except LenIndefForm as err:
5427 raise err.__class__(
5429 klass=self.__class__,
5430 decode_path=decode_path,
5433 l, llen, v = 0, 1, lv[1:]
5435 except DecodeError as err:
5436 raise err.__class__(
5438 klass=self.__class__,
5439 decode_path=decode_path,
5443 raise NotEnoughData(
5444 "encoded length is longer than data",
5445 klass=self.__class__,
5446 decode_path=decode_path,
5450 v, tail = v[:l], v[l:]
5452 sub_offset = offset + tlen + llen
5454 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5455 value_prev = memoryview(v[:0])
5459 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5461 sub_decode_path = decode_path + (str(len(_value)),)
5462 value, v_tail = spec.decode(
5466 decode_path=sub_decode_path,
5468 _ctx_immutable=False,
5470 value_len = value.fulllen
5472 if value_prev.tobytes() > v[:value_len].tobytes():
5473 if ctx_bered or ctx_allow_unordered_set:
5477 "unordered " + self.asn1_type_name,
5478 klass=self.__class__,
5479 decode_path=sub_decode_path,
5482 value_prev = v[:value_len]
5483 _value.append(value)
5484 sub_offset += value_len
5488 obj = self.__class__(
5491 bounds=(self._bound_min, self._bound_max),
5494 default=self.default,
5495 optional=self.optional,
5496 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5498 except BoundsError as err:
5501 klass=self.__class__,
5502 decode_path=decode_path,
5506 if v[:EOC_LEN].tobytes() != EOC:
5509 klass=self.__class__,
5510 decode_path=decode_path,
5515 obj.ber_encoded = ber_encoded
5520 pp_console_row(next(self.pps())),
5521 ", ".join(repr(v) for v in self._value),
5524 def pps(self, decode_path=()):
5527 asn1_type_name=self.asn1_type_name,
5528 obj_name=self.__class__.__name__,
5529 decode_path=decode_path,
5530 optional=self.optional,
5531 default=self == self.default,
5532 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5533 expl=None if self._expl is None else tag_decode(self._expl),
5538 expl_offset=self.expl_offset if self.expled else None,
5539 expl_tlen=self.expl_tlen if self.expled else None,
5540 expl_llen=self.expl_llen if self.expled else None,
5541 expl_vlen=self.expl_vlen if self.expled else None,
5542 expl_lenindef=self.expl_lenindef,
5543 lenindef=self.lenindef,
5544 ber_encoded=self.ber_encoded,
5547 for i, value in enumerate(self._value):
5548 yield value.pps(decode_path=decode_path + (str(i),))
5549 for pp in self.pps_lenindef(decode_path):
5553 class SetOf(SequenceOf):
5554 """``SET OF`` sequence type
5556 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
5559 tag_default = tag_encode(form=TagFormConstructed, num=17)
5560 asn1_type_name = "SET OF"
5563 raws = self._encoded_values()
5566 return b"".join((self.tag, len_encode(len(v)), v))
5568 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5569 return super(SetOf, self)._decode(
5575 ordering_check=True,
5579 def obj_by_path(pypath): # pragma: no cover
5580 """Import object specified as string Python path
5582 Modules must be separated from classes/functions with ``:``.
5584 >>> obj_by_path("foo.bar:Baz")
5585 <class 'foo.bar.Baz'>
5586 >>> obj_by_path("foo.bar:Baz.boo")
5587 <classmethod 'foo.bar.Baz.boo'>
5589 mod, objs = pypath.rsplit(":", 1)
5590 from importlib import import_module
5591 obj = import_module(mod)
5592 for obj_name in objs.split("."):
5593 obj = getattr(obj, obj_name)
5597 def generic_decoder(): # pragma: no cover
5598 # All of this below is a big hack with self references
5599 choice = PrimitiveTypes()
5600 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
5601 choice.specs["SetOf"] = SetOf(schema=choice)
5602 for i in six_xrange(31):
5603 choice.specs["SequenceOf%d" % i] = SequenceOf(
5607 choice.specs["Any"] = Any()
5609 # Class name equals to type name, to omit it from output
5610 class SEQUENCEOF(SequenceOf):
5618 with_decode_path=False,
5619 decode_path_only=(),
5621 def _pprint_pps(pps):
5623 if hasattr(pp, "_fields"):
5625 decode_path_only != () and
5626 pp.decode_path[:len(decode_path_only)] != decode_path_only
5629 if pp.asn1_type_name == Choice.asn1_type_name:
5631 pp_kwargs = pp._asdict()
5632 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
5633 pp = _pp(**pp_kwargs)
5634 yield pp_console_row(
5639 with_colours=with_colours,
5640 with_decode_path=with_decode_path,
5641 decode_path_len_decrease=len(decode_path_only),
5643 for row in pp_console_blob(
5645 decode_path_len_decrease=len(decode_path_only),
5649 for row in _pprint_pps(pp):
5651 return "\n".join(_pprint_pps(obj.pps()))
5652 return SEQUENCEOF(), pprint_any
5655 def main(): # pragma: no cover
5657 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
5658 parser.add_argument(
5662 help="Skip that number of bytes from the beginning",
5664 parser.add_argument(
5666 help="Python paths to dictionary with OIDs, comma separated",
5668 parser.add_argument(
5670 help="Python path to schema definition to use",
5672 parser.add_argument(
5673 "--defines-by-path",
5674 help="Python path to decoder's defines_by_path",
5676 parser.add_argument(
5678 action="store_true",
5679 help="Disallow BER encoding",
5681 parser.add_argument(
5682 "--print-decode-path",
5683 action="store_true",
5684 help="Print decode paths",
5686 parser.add_argument(
5687 "--decode-path-only",
5688 help="Print only specified decode path",
5690 parser.add_argument(
5692 action="store_true",
5693 help="Allow explicit tag out-of-bound",
5695 parser.add_argument(
5697 type=argparse.FileType("rb"),
5698 help="Path to DER file you want to decode",
5700 args = parser.parse_args()
5701 args.DERFile.seek(args.skip)
5702 der = memoryview(args.DERFile.read())
5703 args.DERFile.close()
5705 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
5706 if args.oids else ()
5709 schema = obj_by_path(args.schema)
5710 from functools import partial
5711 pprinter = partial(pprint, big_blobs=True)
5713 schema, pprinter = generic_decoder()
5715 "bered": not args.nobered,
5716 "allow_expl_oob": args.allow_expl_oob,
5718 if args.defines_by_path is not None:
5719 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
5720 obj, tail = schema().decode(der, ctx=ctx)
5724 with_colours=True if environ.get("NO_COLOR") is None else False,
5725 with_decode_path=args.print_decode_path,
5727 () if args.decode_path_only is None else
5728 tuple(args.decode_path_only.split(":"))
5732 print("\nTrailing data: %s" % hexenc(tail))
5735 if __name__ == "__main__":