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().decod(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 either ``impl`` keyword argument or ``impl``
69 class attribute), or ``EXPLICIT`` one (using either ``expl`` keyword
70 argument or ``expl`` class attribute). Both arguments take raw binary
71 string, containing that tag. You can **not** set implicit and explicit
74 There are :py:func:`pyderasn.tag_ctxp` and :py:func:`pyderasn.tag_ctxc`
75 functions, allowing you to easily create ``CONTEXT``
76 ``PRIMITIVE``/``CONSTRUCTED`` tags, by specifying only the required tag
77 number. Pay attention that explicit tags always have *constructed* tag
78 (``tag_ctxc``), but implicit tags for primitive types are primitive
83 >>> Integer(impl=tag_ctxp(1))
85 >>> Integer(expl=tag_ctxc(2))
88 Implicit tag is not explicitly shown.
90 Two objects of the same type, but with different implicit/explicit tags
93 You can get object's effective tag (either default or implicited) through
94 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
97 >>> tag_decode(tag_ctxc(123))
99 >>> klass, form, num = tag_decode(tag_ctxc(123))
100 >>> klass == TagClassContext
102 >>> form == TagFormConstructed
105 To determine if object has explicit tag, use ``expled`` boolean property
106 and ``expl_tag`` property, returning explicit tag's value.
111 Many objects in sequences could be ``OPTIONAL`` and could have
112 ``DEFAULT`` value. You can specify that object's property using
113 corresponding keyword arguments.
115 >>> Integer(optional=True, default=123)
116 INTEGER 123 OPTIONAL DEFAULT
118 Those specifications do not play any role in primitive value encoding,
119 but are taken into account when dealing with sequences holding them. For
120 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
123 class Version(Integer):
129 class TBSCertificate(Sequence):
131 ("version", Version(expl=tag_ctxc(0), default="v1")),
134 When default argument is used and value is not specified, then it equals
142 Some objects give ability to set value size constraints. This is either
143 possible integer value, or allowed length of various strings and
144 sequences. Constraints are set in the following way::
149 And values satisfaction is checked as: ``MIN <= X <= MAX``.
151 For simplicity you can also set bounds the following way::
153 bounded_x = X(bounds=(MIN, MAX))
155 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
161 All objects have ``ready`` boolean property, that tells if object is
162 ready to be encoded. If that kind of action is performed on unready
163 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
165 All objects have ``copy()`` method, that returns their copy, that can be
173 Decoding is performed using :py:meth:`pyderasn.Obj.decode` method.
174 ``offset`` optional argument could be used to set initial object's
175 offset in the binary data, for convenience. It returns decoded object
176 and remaining unmarshalled data (tail). Internally all work is done on
177 ``memoryview(data)``, and you can leave returning tail as a memoryview,
178 by specifying ``leavemm=True`` argument.
180 Also note convenient :py:meth:`pyderasn.Obj.decod` method, that
181 immediately checks and raises if there is non-empty tail.
183 When object is decoded, ``decoded`` property is true and you can safely
184 use following properties:
186 * ``offset`` -- position including initial offset where object's tag starts
187 * ``tlen`` -- length of object's tag
188 * ``llen`` -- length of object's length value
189 * ``vlen`` -- length of object's value
190 * ``tlvlen`` -- length of the whole object
192 Pay attention that those values do **not** include anything related to
193 explicit tag. If you want to know information about it, then use:
195 * ``expled`` -- to know if explicit tag is set
196 * ``expl_offset`` (it is lesser than ``offset``)
199 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
200 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
202 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
205 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
212 You can specify so called context keyword argument during
213 :py:meth:`pyderasn.Obj.decode` invocation. It is dictionary containing
214 various options governing decoding process.
216 Currently available context options:
218 * :ref:`allow_default_values <allow_default_values_ctx>`
219 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
220 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
221 * :ref:`bered <bered_ctx>`
222 * :ref:`defines_by_path <defines_by_path_ctx>`
229 All objects have ``pps()`` method, that is a generator of
230 :py:class:`pyderasn.PP` namedtuple, holding various raw information
231 about the object. If ``pps`` is called on sequences, then all underlying
232 ``PP`` will be yielded.
234 You can use :py:func:`pyderasn.pp_console_row` function, converting
235 those ``PP`` to human readable string. Actually exactly it is used for
236 all object ``repr``. But it is easy to write custom formatters.
238 >>> from pyderasn import pprint
239 >>> encoded = Integer(-12345).encode()
240 >>> obj, tail = Integer().decode(encoded)
241 >>> print(pprint(obj))
242 0 [1,1, 2] INTEGER -12345
246 Example certificate::
248 >>> print(pprint(crt))
249 0 [1,3,1604] Certificate SEQUENCE
250 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
251 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
252 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
253 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
254 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
255 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
257 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
258 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
259 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
260 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
261 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
262 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
263 . . . . . . . 13:02:45:53
265 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
266 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
267 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
269 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
270 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
271 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
276 Let's parse that output, human::
278 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
279 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
280 0 1 2 3 4 5 6 7 8 9 10 11
284 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
290 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
296 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
301 Offset of the object, where its DER/BER encoding begins.
302 Pay attention that it does **not** include explicit tag.
304 If explicit tag exists, then this is its length (tag + encoded length).
306 Length of object's tag. For example CHOICE does not have its own tag,
309 Length of encoded length.
311 Length of encoded value.
313 Visual indentation to show the depth of object in the hierarchy.
315 Object's name inside SEQUENCE/CHOICE.
317 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
318 here. "IMPLICIT" is omitted.
320 Object's class name, if set. Omitted if it is just an ordinary simple
321 value (like with ``algorithm`` in example above).
325 Object's value, if set. Can consist of multiple words (like OCTET/BIT
326 STRINGs above). We see ``v3`` value in Version, because it is named.
327 ``rdnSequence`` is the choice of CHOICE type.
329 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
330 default one, specified in the schema.
332 Shows does object contains any kind of BER encoded data (possibly
333 Sequence holding BER-encoded underlying value).
335 Only applicable to BER encoded data. Indefinite length encoding mark.
337 Only applicable to BER encoded data. If object has BER-specific
338 encoding, then ``BER`` will be shown. It does not depend on indefinite
339 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
340 (and its derivatives), ``SET``, ``SET OF`` could be BERed.
348 ASN.1 structures often have ANY and OCTET STRING fields, that are
349 DEFINED BY some previously met ObjectIdentifier. This library provides
350 ability to specify mapping between some OID and field that must be
351 decoded with specific specification.
358 :py:class:`pyderasn.ObjectIdentifier` field inside
359 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
360 necessary for decoding structures. For example, CMS (:rfc:`5652`)
363 class ContentInfo(Sequence):
365 ("contentType", ContentType(defines=((("content",), {
366 id_digestedData: DigestedData(),
367 id_signedData: SignedData(),
369 ("content", Any(expl=tag_ctxc(0))),
372 ``contentType`` field tells that it defines that ``content`` must be
373 decoded with ``SignedData`` specification, if ``contentType`` equals to
374 ``id-signedData``. The same applies to ``DigestedData``. If
375 ``contentType`` contains unknown OID, then no automatic decoding is
378 You can specify multiple fields, that will be autodecoded -- that is why
379 ``defines`` kwarg is a sequence. You can specify defined field
380 relatively or absolutely to current decode path. For example ``defines``
381 for AlgorithmIdentifier of X.509's
382 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
386 id_ecPublicKey: ECParameters(),
387 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
389 (("..", "subjectPublicKey"), {
390 id_rsaEncryption: RSAPublicKey(),
391 id_GostR3410_2001: OctetString(),
395 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
396 autodecode its parameters inside SPKI's algorithm and its public key
399 Following types can be automatically decoded (DEFINED BY):
401 * :py:class:`pyderasn.Any`
402 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
403 * :py:class:`pyderasn.OctetString`
404 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
405 ``Any``/``BitString``/``OctetString``-s
407 When any of those fields is automatically decoded, then ``.defined``
408 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
409 was defined, ``value`` contains corresponding decoded value. For example
410 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
412 .. _defines_by_path_ctx:
414 defines_by_path context option
415 ______________________________
417 Sometimes you either can not or do not want to explicitly set *defines*
418 in the scheme. You can dynamically apply those definitions when calling
419 ``.decode()`` method.
421 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
422 value must be sequence of following tuples::
424 (decode_path, defines)
426 where ``decode_path`` is a tuple holding so-called decode path to the
427 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
428 ``defines``, holding exactly the same value as accepted in its
429 :ref:`keyword argument <defines>`.
431 For example, again for CMS, you want to automatically decode
432 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
433 structures it may hold. Also, automatically decode ``controlSequence``
436 content_info = ContentInfo().decod(data, ctx={"defines_by_path": (
439 ((("content",), {id_signedData: SignedData()}),),
444 DecodePathDefBy(id_signedData),
449 id_cct_PKIData: PKIData(),
450 id_cct_PKIResponse: PKIResponse(),
456 DecodePathDefBy(id_signedData),
459 DecodePathDefBy(id_cct_PKIResponse),
465 id_cmc_recipientNonce: RecipientNonce(),
466 id_cmc_senderNonce: SenderNonce(),
467 id_cmc_statusInfoV2: CMCStatusInfoV2(),
468 id_cmc_transactionId: TransactionId(),
473 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
474 First function is useful for path construction when some automatic
475 decoding is already done. ``any`` means literally any value it meet --
476 useful for SEQUENCE/SET OF-s.
483 By default PyDERASN accepts only DER encoded data. It always encodes to
484 DER. But you can optionally enable BER decoding with setting ``bered``
485 :ref:`context <ctx>` argument to True. Indefinite lengths and
486 constructed primitive types should be parsed successfully.
488 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
489 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
490 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``
492 * If object has an indefinite length encoding, then its ``lenindef``
493 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
494 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
496 * If object has an indefinite length encoded explicit tag, then
497 ``expl_lenindef`` is set to True.
498 * If object has either any of BER-related encoding (explicit tag
499 indefinite length, object's indefinite length, BER-encoding) or any
500 underlying component has that kind of encoding, then ``bered``
501 attribute is set to True. For example SignedData CMS can have
502 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
503 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
505 EOC (end-of-contents) token's length is taken in advance in object's
508 .. _allow_expl_oob_ctx:
510 Allow explicit tag out-of-bound
511 -------------------------------
513 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
514 one value, more than one object. If you set ``allow_expl_oob`` context
515 option to True, then no error will be raised and that invalid encoding
516 will be silently further processed. But pay attention that offsets and
517 lengths will be invalid in that case.
521 This option should be used only for skipping some decode errors, just
522 to see the decoded structure somehow.
526 .. autoclass:: pyderasn.Obj
534 .. autoclass:: pyderasn.Boolean
539 .. autoclass:: pyderasn.Integer
544 .. autoclass:: pyderasn.BitString
549 .. autoclass:: pyderasn.OctetString
554 .. autoclass:: pyderasn.Null
559 .. autoclass:: pyderasn.ObjectIdentifier
564 .. autoclass:: pyderasn.Enumerated
568 .. autoclass:: pyderasn.CommonString
572 .. autoclass:: pyderasn.NumericString
576 .. autoclass:: pyderasn.PrintableString
581 .. autoclass:: pyderasn.UTCTime
582 :members: __init__, todatetime
586 .. autoclass:: pyderasn.GeneralizedTime
593 .. autoclass:: pyderasn.Choice
598 .. autoclass:: PrimitiveTypes
602 .. autoclass:: pyderasn.Any
610 .. autoclass:: pyderasn.Sequence
615 .. autoclass:: pyderasn.Set
620 .. autoclass:: pyderasn.SequenceOf
625 .. autoclass:: pyderasn.SetOf
631 .. autofunction:: pyderasn.abs_decode_path
632 .. autofunction:: pyderasn.colonize_hex
633 .. autofunction:: pyderasn.hexenc
634 .. autofunction:: pyderasn.hexdec
635 .. autofunction:: pyderasn.tag_encode
636 .. autofunction:: pyderasn.tag_decode
637 .. autofunction:: pyderasn.tag_ctxp
638 .. autofunction:: pyderasn.tag_ctxc
639 .. autoclass:: pyderasn.DecodeError
641 .. autoclass:: pyderasn.NotEnoughData
642 .. autoclass:: pyderasn.ExceedingData
643 .. autoclass:: pyderasn.LenIndefForm
644 .. autoclass:: pyderasn.TagMismatch
645 .. autoclass:: pyderasn.InvalidLength
646 .. autoclass:: pyderasn.InvalidOID
647 .. autoclass:: pyderasn.ObjUnknown
648 .. autoclass:: pyderasn.ObjNotReady
649 .. autoclass:: pyderasn.InvalidValueType
650 .. autoclass:: pyderasn.BoundsError
653 from codecs import getdecoder
654 from codecs import getencoder
655 from collections import namedtuple
656 from collections import OrderedDict
657 from copy import copy
658 from datetime import datetime
659 from math import ceil
660 from os import environ
661 from string import ascii_letters
662 from string import digits
663 from unicodedata import category as unicat
665 from six import add_metaclass
666 from six import binary_type
667 from six import byte2int
668 from six import indexbytes
669 from six import int2byte
670 from six import integer_types
671 from six import iterbytes
672 from six import iteritems
673 from six import itervalues
675 from six import string_types
676 from six import text_type
677 from six import unichr as six_unichr
678 from six.moves import xrange as six_xrange
682 from termcolor import colored
683 except ImportError: # pragma: no cover
684 def colored(what, *args, **kwargs):
730 "TagClassApplication",
734 "TagFormConstructed",
745 TagClassUniversal = 0
746 TagClassApplication = 1 << 6
747 TagClassContext = 1 << 7
748 TagClassPrivate = 1 << 6 | 1 << 7
750 TagFormConstructed = 1 << 5
753 TagClassApplication: "APPLICATION ",
754 TagClassPrivate: "PRIVATE ",
755 TagClassUniversal: "UNIV ",
759 LENINDEF = b"\x80" # length indefinite mark
760 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
763 ########################################################################
765 ########################################################################
767 class ASN1Error(ValueError):
771 class DecodeError(ASN1Error):
772 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
774 :param str msg: reason of decode failing
775 :param klass: optional exact DecodeError inherited class (like
776 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
777 :py:exc:`InvalidLength`)
778 :param decode_path: tuple of strings. It contains human
779 readable names of the fields through which
780 decoding process has passed
781 :param int offset: binary offset where failure happened
783 super(DecodeError, self).__init__()
786 self.decode_path = decode_path
792 "" if self.klass is None else self.klass.__name__,
794 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
795 if len(self.decode_path) > 0 else ""
797 ("(at %d)" % self.offset) if self.offset > 0 else "",
803 return "%s(%s)" % (self.__class__.__name__, self)
806 class NotEnoughData(DecodeError):
810 class ExceedingData(ASN1Error):
811 def __init__(self, nbytes):
812 super(ExceedingData, self).__init__()
816 return "%d trailing bytes" % self.nbytes
819 return "%s(%s)" % (self.__class__.__name__, self)
822 class LenIndefForm(DecodeError):
826 class TagMismatch(DecodeError):
830 class InvalidLength(DecodeError):
834 class InvalidOID(DecodeError):
838 class ObjUnknown(ASN1Error):
839 def __init__(self, name):
840 super(ObjUnknown, self).__init__()
844 return "object is unknown: %s" % self.name
847 return "%s(%s)" % (self.__class__.__name__, self)
850 class ObjNotReady(ASN1Error):
851 def __init__(self, name):
852 super(ObjNotReady, self).__init__()
856 return "object is not ready: %s" % self.name
859 return "%s(%s)" % (self.__class__.__name__, self)
862 class InvalidValueType(ASN1Error):
863 def __init__(self, expected_types):
864 super(InvalidValueType, self).__init__()
865 self.expected_types = expected_types
868 return "invalid value type, expected: %s" % ", ".join(
869 [repr(t) for t in self.expected_types]
873 return "%s(%s)" % (self.__class__.__name__, self)
876 class BoundsError(ASN1Error):
877 def __init__(self, bound_min, value, bound_max):
878 super(BoundsError, self).__init__()
879 self.bound_min = bound_min
881 self.bound_max = bound_max
884 return "unsatisfied bounds: %s <= %s <= %s" % (
891 return "%s(%s)" % (self.__class__.__name__, self)
894 ########################################################################
896 ########################################################################
898 _hexdecoder = getdecoder("hex")
899 _hexencoder = getencoder("hex")
903 """Binary data to hexadecimal string convert
905 return _hexdecoder(data)[0]
909 """Hexadecimal string to binary data convert
911 return _hexencoder(data)[0].decode("ascii")
914 def int_bytes_len(num, byte_len=8):
917 return int(ceil(float(num.bit_length()) / byte_len))
920 def zero_ended_encode(num):
921 octets = bytearray(int_bytes_len(num, 7))
923 octets[i] = num & 0x7F
927 octets[i] = 0x80 | (num & 0x7F)
933 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
934 """Encode tag to binary form
936 :param int num: tag's number
937 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
938 :py:data:`pyderasn.TagClassContext`,
939 :py:data:`pyderasn.TagClassApplication`,
940 :py:data:`pyderasn.TagClassPrivate`)
941 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
942 :py:data:`pyderasn.TagFormConstructed`)
946 return int2byte(klass | form | num)
947 # [XX|X|11111][1.......][1.......] ... [0.......]
948 return int2byte(klass | form | 31) + zero_ended_encode(num)
952 """Decode tag from binary form
956 No validation is performed, assuming that it has already passed.
958 It returns tuple with three integers, as
959 :py:func:`pyderasn.tag_encode` accepts.
961 first_octet = byte2int(tag)
962 klass = first_octet & 0xC0
963 form = first_octet & 0x20
964 if first_octet & 0x1F < 0x1F:
965 return (klass, form, first_octet & 0x1F)
967 for octet in iterbytes(tag[1:]):
970 return (klass, form, num)
974 """Create CONTEXT PRIMITIVE tag
976 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
980 """Create CONTEXT CONSTRUCTED tag
982 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
986 """Take off tag from the data
988 :returns: (encoded tag, tag length, remaining data)
991 raise NotEnoughData("no data at all")
992 if byte2int(data) & 0x1F < 31:
993 return data[:1], 1, data[1:]
998 raise DecodeError("unfinished tag")
999 if indexbytes(data, i) & 0x80 == 0:
1002 return data[:i], i, data[i:]
1008 octets = bytearray(int_bytes_len(l) + 1)
1009 octets[0] = 0x80 | (len(octets) - 1)
1010 for i in six_xrange(len(octets) - 1, 0, -1):
1011 octets[i] = l & 0xFF
1013 return bytes(octets)
1016 def len_decode(data):
1019 :returns: (decoded length, length's length, remaining data)
1020 :raises LenIndefForm: if indefinite form encoding is met
1023 raise NotEnoughData("no data at all")
1024 first_octet = byte2int(data)
1025 if first_octet & 0x80 == 0:
1026 return first_octet, 1, data[1:]
1027 octets_num = first_octet & 0x7F
1028 if octets_num + 1 > len(data):
1029 raise NotEnoughData("encoded length is longer than data")
1031 raise LenIndefForm()
1032 if byte2int(data[1:]) == 0:
1033 raise DecodeError("leading zeros")
1035 for v in iterbytes(data[1:1 + octets_num]):
1038 raise DecodeError("long form instead of short one")
1039 return l, 1 + octets_num, data[1 + octets_num:]
1042 ########################################################################
1044 ########################################################################
1046 class AutoAddSlots(type):
1047 def __new__(cls, name, bases, _dict):
1048 _dict["__slots__"] = _dict.get("__slots__", ())
1049 return type.__new__(cls, name, bases, _dict)
1052 @add_metaclass(AutoAddSlots)
1054 """Common ASN.1 object class
1056 All ASN.1 types are inherited from it. It has metaclass that
1057 automatically adds ``__slots__`` to all inherited classes.
1081 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1082 self._expl = getattr(self, "expl", None) if expl is None else expl
1083 if self.tag != self.tag_default and self._expl is not None:
1084 raise ValueError("implicit and explicit tags can not be set simultaneously")
1085 if default is not None:
1087 self.optional = optional
1088 self.offset, self.llen, self.vlen = _decoded
1090 self.expl_lenindef = False
1091 self.lenindef = False
1092 self.ber_encoded = False
1095 def ready(self): # pragma: no cover
1096 """Is object ready to be encoded?
1098 raise NotImplementedError()
1100 def _assert_ready(self):
1102 raise ObjNotReady(self.__class__.__name__)
1106 """Is either object or any elements inside is BER encoded?
1108 return self.expl_lenindef or self.lenindef or self.ber_encoded
1112 """Is object decoded?
1114 return (self.llen + self.vlen) > 0
1116 def copy(self): # pragma: no cover
1117 """Make a copy of object, safe to be mutated
1119 raise NotImplementedError()
1123 """See :ref:`decoding`
1125 return len(self.tag)
1129 """See :ref:`decoding`
1131 return self.tlen + self.llen + self.vlen
1133 def __str__(self): # pragma: no cover
1134 return self.__bytes__() if PY2 else self.__unicode__()
1136 def __ne__(self, their):
1137 return not(self == their)
1139 def __gt__(self, their): # pragma: no cover
1140 return not(self < their)
1142 def __le__(self, their): # pragma: no cover
1143 return (self == their) or (self < their)
1145 def __ge__(self, their): # pragma: no cover
1146 return (self == their) or (self > their)
1148 def _encode(self): # pragma: no cover
1149 raise NotImplementedError()
1151 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1152 raise NotImplementedError()
1155 """Encode the structure
1157 :returns: DER representation
1159 raw = self._encode()
1160 if self._expl is None:
1162 return b"".join((self._expl, len_encode(len(raw)), raw))
1172 _ctx_immutable=True,
1176 :param data: either binary or memoryview
1177 :param int offset: initial data's offset
1178 :param bool leavemm: do we need to leave memoryview of remaining
1179 data as is, or convert it to bytes otherwise
1180 :param ctx: optional :ref:`context <ctx>` governing decoding process
1181 :param tag_only: decode only the tag, without length and contents
1182 (used only in Choice and Set structures, trying to
1183 determine if tag satisfies the scheme)
1184 :param _ctx_immutable: do we need to copy ``ctx`` before using it
1185 :returns: (Obj, remaining data)
1187 .. seealso:: :ref:`decoding`
1191 elif _ctx_immutable:
1193 tlv = memoryview(data)
1194 if self._expl is None:
1195 result = self._decode(
1198 decode_path=decode_path,
1207 t, tlen, lv = tag_strip(tlv)
1208 except DecodeError as err:
1209 raise err.__class__(
1211 klass=self.__class__,
1212 decode_path=decode_path,
1217 klass=self.__class__,
1218 decode_path=decode_path,
1222 l, llen, v = len_decode(lv)
1223 except LenIndefForm as err:
1224 if not ctx.get("bered", False):
1225 raise err.__class__(
1227 klass=self.__class__,
1228 decode_path=decode_path,
1232 offset += tlen + llen
1233 result = self._decode(
1236 decode_path=decode_path,
1240 if tag_only: # pragma: no cover
1243 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1244 if eoc_expected.tobytes() != EOC:
1247 klass=self.__class__,
1248 decode_path=decode_path,
1252 obj.expl_lenindef = True
1253 except DecodeError as err:
1254 raise err.__class__(
1256 klass=self.__class__,
1257 decode_path=decode_path,
1262 raise NotEnoughData(
1263 "encoded length is longer than data",
1264 klass=self.__class__,
1265 decode_path=decode_path,
1268 result = self._decode(
1270 offset=offset + tlen + llen,
1271 decode_path=decode_path,
1275 if tag_only: # pragma: no cover
1278 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1280 "explicit tag out-of-bound, longer than data",
1281 klass=self.__class__,
1282 decode_path=decode_path,
1285 return obj, (tail if leavemm else tail.tobytes())
1287 def decod(self, data, offset=0, decode_path=(), ctx=None):
1288 """Decode the data, check that tail is empty
1290 :raises ExceedingData: if tail is not empty
1292 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1293 (decode without tail) that also checks that there is no
1296 obj, tail = self.decode(
1299 decode_path=decode_path,
1304 raise ExceedingData(len(tail))
1309 """See :ref:`decoding`
1311 return self._expl is not None
1315 """See :ref:`decoding`
1320 def expl_tlen(self):
1321 """See :ref:`decoding`
1323 return len(self._expl)
1326 def expl_llen(self):
1327 """See :ref:`decoding`
1329 if self.expl_lenindef:
1331 return len(len_encode(self.tlvlen))
1334 def expl_offset(self):
1335 """See :ref:`decoding`
1337 return self.offset - self.expl_tlen - self.expl_llen
1340 def expl_vlen(self):
1341 """See :ref:`decoding`
1346 def expl_tlvlen(self):
1347 """See :ref:`decoding`
1349 return self.expl_tlen + self.expl_llen + self.expl_vlen
1352 def fulloffset(self):
1353 """See :ref:`decoding`
1355 return self.expl_offset if self.expled else self.offset
1359 """See :ref:`decoding`
1361 return self.expl_tlvlen if self.expled else self.tlvlen
1363 def pps_lenindef(self, decode_path):
1364 if self.lenindef and not (
1365 getattr(self, "defined", None) is not None and
1366 self.defined[1].lenindef
1369 asn1_type_name="EOC",
1371 decode_path=decode_path,
1373 self.offset + self.tlvlen -
1374 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1382 if self.expl_lenindef:
1384 asn1_type_name="EOC",
1385 obj_name="EXPLICIT",
1386 decode_path=decode_path,
1387 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1396 class DecodePathDefBy(object):
1397 """DEFINED BY representation inside decode path
1399 __slots__ = ("defined_by",)
1401 def __init__(self, defined_by):
1402 self.defined_by = defined_by
1404 def __ne__(self, their):
1405 return not(self == their)
1407 def __eq__(self, their):
1408 if not isinstance(their, self.__class__):
1410 return self.defined_by == their.defined_by
1413 return "DEFINED BY " + str(self.defined_by)
1416 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1419 ########################################################################
1421 ########################################################################
1423 PP = namedtuple("PP", (
1451 asn1_type_name="unknown",
1468 expl_lenindef=False,
1499 def _colourize(what, colour, with_colours, attrs=("bold",)):
1500 return colored(what, colour, attrs=attrs) if with_colours else what
1503 def colonize_hex(hexed):
1504 """Separate hexadecimal string with colons
1506 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1515 with_decode_path=False,
1516 decode_path_len_decrease=0,
1523 " " if pp.expl_offset is None else
1524 ("-%d" % (pp.offset - pp.expl_offset))
1526 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1528 col = _colourize(col, "red", with_colours, ())
1529 col += _colourize("B", "red", with_colours) if pp.bered else " "
1531 col = "[%d,%d,%4d]%s" % (
1535 LENINDEF_PP_CHAR if pp.lenindef else " "
1537 col = _colourize(col, "green", with_colours, ())
1539 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1540 if decode_path_len > 0:
1541 cols.append(" ." * decode_path_len)
1542 ent = pp.decode_path[-1]
1543 if isinstance(ent, DecodePathDefBy):
1544 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1545 value = str(ent.defined_by)
1548 len(oid_maps) > 0 and
1549 ent.defined_by.asn1_type_name ==
1550 ObjectIdentifier.asn1_type_name
1552 for oid_map in oid_maps:
1553 oid_name = oid_map.get(value)
1554 if oid_name is not None:
1555 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1557 if oid_name is None:
1558 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1560 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1561 if pp.expl is not None:
1562 klass, _, num = pp.expl
1563 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1564 cols.append(_colourize(col, "blue", with_colours))
1565 if pp.impl is not None:
1566 klass, _, num = pp.impl
1567 col = "[%s%d]" % (TagClassReprs[klass], num)
1568 cols.append(_colourize(col, "blue", with_colours))
1569 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1570 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1572 cols.append(_colourize("BER", "red", with_colours))
1573 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1574 if pp.value is not None:
1576 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1578 len(oid_maps) > 0 and
1579 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1581 for oid_map in oid_maps:
1582 oid_name = oid_map.get(value)
1583 if oid_name is not None:
1584 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1586 if pp.asn1_type_name == Integer.asn1_type_name:
1587 hex_repr = hex(int(pp.obj._value))[2:].upper()
1588 if len(hex_repr) % 2 != 0:
1589 hex_repr = "0" + hex_repr
1590 cols.append(_colourize(
1591 "(%s)" % colonize_hex(hex_repr),
1596 if isinstance(pp.blob, binary_type):
1597 cols.append(hexenc(pp.blob))
1598 elif isinstance(pp.blob, tuple):
1599 cols.append(", ".join(pp.blob))
1601 cols.append(_colourize("OPTIONAL", "red", with_colours))
1603 cols.append(_colourize("DEFAULT", "red", with_colours))
1604 if with_decode_path:
1605 cols.append(_colourize(
1606 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1610 return " ".join(cols)
1613 def pp_console_blob(pp, decode_path_len_decrease=0):
1614 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1615 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1616 if decode_path_len > 0:
1617 cols.append(" ." * (decode_path_len + 1))
1618 if isinstance(pp.blob, binary_type):
1619 blob = hexenc(pp.blob).upper()
1620 for i in six_xrange(0, len(blob), 32):
1621 chunk = blob[i:i + 32]
1622 yield " ".join(cols + [colonize_hex(chunk)])
1623 elif isinstance(pp.blob, tuple):
1624 yield " ".join(cols + [", ".join(pp.blob)])
1632 with_decode_path=False,
1633 decode_path_only=(),
1635 """Pretty print object
1637 :param Obj obj: object you want to pretty print
1638 :param oid_maps: list of ``OID <-> humand readable string`` dictionary.
1639 When OID from it is met, then its humand readable form
1641 :param big_blobs: if large binary objects are met (like OctetString
1642 values), do we need to print them too, on separate
1644 :param with_colours: colourize output, if ``termcolor`` library
1646 :param with_decode_path: print decode path
1647 :param decode_path_only: print only that specified decode path
1649 def _pprint_pps(pps):
1651 if hasattr(pp, "_fields"):
1653 decode_path_only != () and
1655 str(p) for p in pp.decode_path[:len(decode_path_only)]
1656 ) != decode_path_only
1660 yield pp_console_row(
1665 with_colours=with_colours,
1666 with_decode_path=with_decode_path,
1667 decode_path_len_decrease=len(decode_path_only),
1669 for row in pp_console_blob(
1671 decode_path_len_decrease=len(decode_path_only),
1675 yield pp_console_row(
1680 with_colours=with_colours,
1681 with_decode_path=with_decode_path,
1682 decode_path_len_decrease=len(decode_path_only),
1685 for row in _pprint_pps(pp):
1687 return "\n".join(_pprint_pps(obj.pps()))
1690 ########################################################################
1691 # ASN.1 primitive types
1692 ########################################################################
1695 """``BOOLEAN`` boolean type
1697 >>> b = Boolean(True)
1699 >>> b == Boolean(True)
1705 tag_default = tag_encode(1)
1706 asn1_type_name = "BOOLEAN"
1718 :param value: set the value. Either boolean type, or
1719 :py:class:`pyderasn.Boolean` object
1720 :param bytes impl: override default tag with ``IMPLICIT`` one
1721 :param bytes expl: override default tag with ``EXPLICIT`` one
1722 :param default: set default value. Type same as in ``value``
1723 :param bool optional: is object ``OPTIONAL`` in sequence
1725 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1726 self._value = None if value is None else self._value_sanitize(value)
1727 if default is not None:
1728 default = self._value_sanitize(default)
1729 self.default = self.__class__(
1735 self._value = default
1737 def _value_sanitize(self, value):
1738 if isinstance(value, bool):
1740 if issubclass(value.__class__, Boolean):
1742 raise InvalidValueType((self.__class__, bool))
1746 return self._value is not None
1749 obj = self.__class__()
1750 obj._value = self._value
1752 obj._expl = self._expl
1753 obj.default = self.default
1754 obj.optional = self.optional
1755 obj.offset = self.offset
1756 obj.llen = self.llen
1757 obj.vlen = self.vlen
1758 obj.expl_lenindef = self.expl_lenindef
1759 obj.lenindef = self.lenindef
1760 obj.ber_encoded = self.ber_encoded
1763 def __nonzero__(self):
1764 self._assert_ready()
1768 self._assert_ready()
1771 def __eq__(self, their):
1772 if isinstance(their, bool):
1773 return self._value == their
1774 if not issubclass(their.__class__, Boolean):
1777 self._value == their._value and
1778 self.tag == their.tag and
1779 self._expl == their._expl
1790 return self.__class__(
1792 impl=self.tag if impl is None else impl,
1793 expl=self._expl if expl is None else expl,
1794 default=self.default if default is None else default,
1795 optional=self.optional if optional is None else optional,
1799 self._assert_ready()
1803 (b"\xFF" if self._value else b"\x00"),
1806 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1808 t, _, lv = tag_strip(tlv)
1809 except DecodeError as err:
1810 raise err.__class__(
1812 klass=self.__class__,
1813 decode_path=decode_path,
1818 klass=self.__class__,
1819 decode_path=decode_path,
1825 l, _, v = len_decode(lv)
1826 except DecodeError as err:
1827 raise err.__class__(
1829 klass=self.__class__,
1830 decode_path=decode_path,
1834 raise InvalidLength(
1835 "Boolean's length must be equal to 1",
1836 klass=self.__class__,
1837 decode_path=decode_path,
1841 raise NotEnoughData(
1842 "encoded length is longer than data",
1843 klass=self.__class__,
1844 decode_path=decode_path,
1847 first_octet = byte2int(v)
1849 if first_octet == 0:
1851 elif first_octet == 0xFF:
1853 elif ctx.get("bered", False):
1858 "unacceptable Boolean value",
1859 klass=self.__class__,
1860 decode_path=decode_path,
1863 obj = self.__class__(
1867 default=self.default,
1868 optional=self.optional,
1869 _decoded=(offset, 1, 1),
1871 obj.ber_encoded = ber_encoded
1875 return pp_console_row(next(self.pps()))
1877 def pps(self, decode_path=()):
1880 asn1_type_name=self.asn1_type_name,
1881 obj_name=self.__class__.__name__,
1882 decode_path=decode_path,
1883 value=str(self._value) if self.ready else None,
1884 optional=self.optional,
1885 default=self == self.default,
1886 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1887 expl=None if self._expl is None else tag_decode(self._expl),
1892 expl_offset=self.expl_offset if self.expled else None,
1893 expl_tlen=self.expl_tlen if self.expled else None,
1894 expl_llen=self.expl_llen if self.expled else None,
1895 expl_vlen=self.expl_vlen if self.expled else None,
1896 expl_lenindef=self.expl_lenindef,
1897 ber_encoded=self.ber_encoded,
1900 for pp in self.pps_lenindef(decode_path):
1905 """``INTEGER`` integer type
1907 >>> b = Integer(-123)
1909 >>> b == Integer(-123)
1914 >>> Integer(2, bounds=(1, 3))
1916 >>> Integer(5, bounds=(1, 3))
1917 Traceback (most recent call last):
1918 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1922 class Version(Integer):
1929 >>> v = Version("v1")
1936 {'v3': 2, 'v1': 0, 'v2': 1}
1938 __slots__ = ("specs", "_bound_min", "_bound_max")
1939 tag_default = tag_encode(2)
1940 asn1_type_name = "INTEGER"
1954 :param value: set the value. Either integer type, named value
1955 (if ``schema`` is specified in the class), or
1956 :py:class:`pyderasn.Integer` object
1957 :param bounds: set ``(MIN, MAX)`` value constraint.
1958 (-inf, +inf) by default
1959 :param bytes impl: override default tag with ``IMPLICIT`` one
1960 :param bytes expl: override default tag with ``EXPLICIT`` one
1961 :param default: set default value. Type same as in ``value``
1962 :param bool optional: is object ``OPTIONAL`` in sequence
1964 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
1966 specs = getattr(self, "schema", {}) if _specs is None else _specs
1967 self.specs = specs if isinstance(specs, dict) else dict(specs)
1968 self._bound_min, self._bound_max = getattr(
1971 (float("-inf"), float("+inf")),
1972 ) if bounds is None else bounds
1973 if value is not None:
1974 self._value = self._value_sanitize(value)
1975 if default is not None:
1976 default = self._value_sanitize(default)
1977 self.default = self.__class__(
1983 if self._value is None:
1984 self._value = default
1986 def _value_sanitize(self, value):
1987 if isinstance(value, integer_types):
1989 elif issubclass(value.__class__, Integer):
1990 value = value._value
1991 elif isinstance(value, str):
1992 value = self.specs.get(value)
1994 raise ObjUnknown("integer value: %s" % value)
1996 raise InvalidValueType((self.__class__, int, str))
1997 if not self._bound_min <= value <= self._bound_max:
1998 raise BoundsError(self._bound_min, value, self._bound_max)
2003 return self._value is not None
2006 obj = self.__class__(_specs=self.specs)
2007 obj._value = self._value
2008 obj._bound_min = self._bound_min
2009 obj._bound_max = self._bound_max
2011 obj._expl = self._expl
2012 obj.default = self.default
2013 obj.optional = self.optional
2014 obj.offset = self.offset
2015 obj.llen = self.llen
2016 obj.vlen = self.vlen
2017 obj.expl_lenindef = self.expl_lenindef
2018 obj.lenindef = self.lenindef
2019 obj.ber_encoded = self.ber_encoded
2023 self._assert_ready()
2024 return int(self._value)
2027 self._assert_ready()
2030 bytes(self._expl or b"") +
2031 str(self._value).encode("ascii"),
2034 def __eq__(self, their):
2035 if isinstance(their, integer_types):
2036 return self._value == their
2037 if not issubclass(their.__class__, Integer):
2040 self._value == their._value and
2041 self.tag == their.tag and
2042 self._expl == their._expl
2045 def __lt__(self, their):
2046 return self._value < their._value
2050 for name, value in iteritems(self.specs):
2051 if value == self._value:
2064 return self.__class__(
2067 (self._bound_min, self._bound_max)
2068 if bounds is None else bounds
2070 impl=self.tag if impl is None else impl,
2071 expl=self._expl if expl is None else expl,
2072 default=self.default if default is None else default,
2073 optional=self.optional if optional is None else optional,
2078 self._assert_ready()
2082 octets = bytearray([0])
2086 octets = bytearray()
2088 octets.append((value & 0xFF) ^ 0xFF)
2090 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2093 octets = bytearray()
2095 octets.append(value & 0xFF)
2097 if octets[-1] & 0x80 > 0:
2100 octets = bytes(octets)
2102 bytes_len = ceil(value.bit_length() / 8) or 1
2105 octets = value.to_bytes(
2110 except OverflowError:
2114 return b"".join((self.tag, len_encode(len(octets)), octets))
2116 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2118 t, _, lv = tag_strip(tlv)
2119 except DecodeError as err:
2120 raise err.__class__(
2122 klass=self.__class__,
2123 decode_path=decode_path,
2128 klass=self.__class__,
2129 decode_path=decode_path,
2135 l, llen, v = len_decode(lv)
2136 except DecodeError as err:
2137 raise err.__class__(
2139 klass=self.__class__,
2140 decode_path=decode_path,
2144 raise NotEnoughData(
2145 "encoded length is longer than data",
2146 klass=self.__class__,
2147 decode_path=decode_path,
2151 raise NotEnoughData(
2153 klass=self.__class__,
2154 decode_path=decode_path,
2157 v, tail = v[:l], v[l:]
2158 first_octet = byte2int(v)
2160 second_octet = byte2int(v[1:])
2162 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2163 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2166 "non normalized integer",
2167 klass=self.__class__,
2168 decode_path=decode_path,
2173 if first_octet & 0x80 > 0:
2174 octets = bytearray()
2175 for octet in bytearray(v):
2176 octets.append(octet ^ 0xFF)
2177 for octet in octets:
2178 value = (value << 8) | octet
2182 for octet in bytearray(v):
2183 value = (value << 8) | octet
2185 value = int.from_bytes(v, byteorder="big", signed=True)
2187 obj = self.__class__(
2189 bounds=(self._bound_min, self._bound_max),
2192 default=self.default,
2193 optional=self.optional,
2195 _decoded=(offset, llen, l),
2197 except BoundsError as err:
2200 klass=self.__class__,
2201 decode_path=decode_path,
2207 return pp_console_row(next(self.pps()))
2209 def pps(self, decode_path=()):
2212 asn1_type_name=self.asn1_type_name,
2213 obj_name=self.__class__.__name__,
2214 decode_path=decode_path,
2215 value=(self.named or str(self._value)) if self.ready else None,
2216 optional=self.optional,
2217 default=self == self.default,
2218 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2219 expl=None if self._expl is None else tag_decode(self._expl),
2224 expl_offset=self.expl_offset if self.expled else None,
2225 expl_tlen=self.expl_tlen if self.expled else None,
2226 expl_llen=self.expl_llen if self.expled else None,
2227 expl_vlen=self.expl_vlen if self.expled else None,
2228 expl_lenindef=self.expl_lenindef,
2231 for pp in self.pps_lenindef(decode_path):
2235 SET01 = frozenset(("0", "1"))
2238 class BitString(Obj):
2239 """``BIT STRING`` bit string type
2241 >>> BitString(b"hello world")
2242 BIT STRING 88 bits 68656c6c6f20776f726c64
2245 >>> b == b"hello world"
2250 >>> BitString("'0A3B5F291CD'H")
2251 BIT STRING 44 bits 0a3b5f291cd0
2252 >>> b = BitString("'010110000000'B")
2253 BIT STRING 12 bits 5800
2256 >>> b[0], b[1], b[2], b[3]
2257 (False, True, False, True)
2261 [False, True, False, True, True, False, False, False, False, False, False, False]
2265 class KeyUsage(BitString):
2267 ("digitalSignature", 0),
2268 ("nonRepudiation", 1),
2269 ("keyEncipherment", 2),
2272 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2273 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2275 ['nonRepudiation', 'keyEncipherment']
2277 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2281 Pay attention that BIT STRING can be encoded both in primitive
2282 and constructed forms. Decoder always checks constructed form tag
2283 additionally to specified primitive one. If BER decoding is
2284 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2285 of DER restrictions.
2287 __slots__ = ("tag_constructed", "specs", "defined")
2288 tag_default = tag_encode(3)
2289 asn1_type_name = "BIT STRING"
2302 :param value: set the value. Either binary type, tuple of named
2303 values (if ``schema`` is specified in the class),
2304 string in ``'XXX...'B`` form, or
2305 :py:class:`pyderasn.BitString` object
2306 :param bytes impl: override default tag with ``IMPLICIT`` one
2307 :param bytes expl: override default tag with ``EXPLICIT`` one
2308 :param default: set default value. Type same as in ``value``
2309 :param bool optional: is object ``OPTIONAL`` in sequence
2311 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2312 specs = getattr(self, "schema", {}) if _specs is None else _specs
2313 self.specs = specs if isinstance(specs, dict) else dict(specs)
2314 self._value = None if value is None else self._value_sanitize(value)
2315 if default is not None:
2316 default = self._value_sanitize(default)
2317 self.default = self.__class__(
2323 self._value = default
2325 tag_klass, _, tag_num = tag_decode(self.tag)
2326 self.tag_constructed = tag_encode(
2328 form=TagFormConstructed,
2332 def _bits2octets(self, bits):
2333 if len(self.specs) > 0:
2334 bits = bits.rstrip("0")
2336 bits += "0" * ((8 - (bit_len % 8)) % 8)
2337 octets = bytearray(len(bits) // 8)
2338 for i in six_xrange(len(octets)):
2339 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2340 return bit_len, bytes(octets)
2342 def _value_sanitize(self, value):
2343 if isinstance(value, (string_types, binary_type)):
2345 isinstance(value, string_types) and
2346 value.startswith("'")
2348 if value.endswith("'B"):
2350 if not frozenset(value) <= SET01:
2351 raise ValueError("B's coding contains unacceptable chars")
2352 return self._bits2octets(value)
2353 if value.endswith("'H"):
2357 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2359 if isinstance(value, binary_type):
2360 return (len(value) * 8, value)
2361 raise InvalidValueType((self.__class__, string_types, binary_type))
2362 if isinstance(value, tuple):
2365 isinstance(value[0], integer_types) and
2366 isinstance(value[1], binary_type)
2371 bit = self.specs.get(name)
2373 raise ObjUnknown("BitString value: %s" % name)
2376 return self._bits2octets("")
2377 bits = frozenset(bits)
2378 return self._bits2octets("".join(
2379 ("1" if bit in bits else "0")
2380 for bit in six_xrange(max(bits) + 1)
2382 if issubclass(value.__class__, BitString):
2384 raise InvalidValueType((self.__class__, binary_type, string_types))
2388 return self._value is not None
2391 obj = self.__class__(_specs=self.specs)
2393 if value is not None:
2394 value = (value[0], value[1])
2397 obj._expl = self._expl
2398 obj.default = self.default
2399 obj.optional = self.optional
2400 obj.offset = self.offset
2401 obj.llen = self.llen
2402 obj.vlen = self.vlen
2403 obj.expl_lenindef = self.expl_lenindef
2404 obj.lenindef = self.lenindef
2405 obj.ber_encoded = self.ber_encoded
2409 self._assert_ready()
2410 for i in six_xrange(self._value[0]):
2415 self._assert_ready()
2416 return self._value[0]
2418 def __bytes__(self):
2419 self._assert_ready()
2420 return self._value[1]
2422 def __eq__(self, their):
2423 if isinstance(their, bytes):
2424 return self._value[1] == their
2425 if not issubclass(their.__class__, BitString):
2428 self._value == their._value and
2429 self.tag == their.tag and
2430 self._expl == their._expl
2435 return [name for name, bit in iteritems(self.specs) if self[bit]]
2445 return self.__class__(
2447 impl=self.tag if impl is None else impl,
2448 expl=self._expl if expl is None else expl,
2449 default=self.default if default is None else default,
2450 optional=self.optional if optional is None else optional,
2454 def __getitem__(self, key):
2455 if isinstance(key, int):
2456 bit_len, octets = self._value
2460 byte2int(memoryview(octets)[key // 8:]) >>
2463 if isinstance(key, string_types):
2464 value = self.specs.get(key)
2466 raise ObjUnknown("BitString value: %s" % key)
2468 raise InvalidValueType((int, str))
2471 self._assert_ready()
2472 bit_len, octets = self._value
2475 len_encode(len(octets) + 1),
2476 int2byte((8 - bit_len % 8) % 8),
2480 def _decode_chunk(self, lv, offset, decode_path):
2482 l, llen, v = len_decode(lv)
2483 except DecodeError as err:
2484 raise err.__class__(
2486 klass=self.__class__,
2487 decode_path=decode_path,
2491 raise NotEnoughData(
2492 "encoded length is longer than data",
2493 klass=self.__class__,
2494 decode_path=decode_path,
2498 raise NotEnoughData(
2500 klass=self.__class__,
2501 decode_path=decode_path,
2504 pad_size = byte2int(v)
2505 if l == 1 and pad_size != 0:
2507 "invalid empty value",
2508 klass=self.__class__,
2509 decode_path=decode_path,
2515 klass=self.__class__,
2516 decode_path=decode_path,
2519 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2522 klass=self.__class__,
2523 decode_path=decode_path,
2526 v, tail = v[:l], v[l:]
2527 obj = self.__class__(
2528 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2531 default=self.default,
2532 optional=self.optional,
2534 _decoded=(offset, llen, l),
2538 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2540 t, tlen, lv = tag_strip(tlv)
2541 except DecodeError as err:
2542 raise err.__class__(
2544 klass=self.__class__,
2545 decode_path=decode_path,
2549 if tag_only: # pragma: no cover
2551 return self._decode_chunk(lv, offset, decode_path)
2552 if t == self.tag_constructed:
2553 if not ctx.get("bered", False):
2555 "unallowed BER constructed encoding",
2556 klass=self.__class__,
2557 decode_path=decode_path,
2560 if tag_only: # pragma: no cover
2564 l, llen, v = len_decode(lv)
2565 except LenIndefForm:
2566 llen, l, v = 1, 0, lv[1:]
2568 except DecodeError as err:
2569 raise err.__class__(
2571 klass=self.__class__,
2572 decode_path=decode_path,
2576 raise NotEnoughData(
2577 "encoded length is longer than data",
2578 klass=self.__class__,
2579 decode_path=decode_path,
2582 if not lenindef and l == 0:
2583 raise NotEnoughData(
2585 klass=self.__class__,
2586 decode_path=decode_path,
2590 sub_offset = offset + tlen + llen
2594 if v[:EOC_LEN].tobytes() == EOC:
2601 "chunk out of bounds",
2602 klass=self.__class__,
2603 decode_path=decode_path + (str(len(chunks) - 1),),
2604 offset=chunks[-1].offset,
2606 sub_decode_path = decode_path + (str(len(chunks)),)
2608 chunk, v_tail = BitString().decode(
2611 decode_path=sub_decode_path,
2614 _ctx_immutable=False,
2618 "expected BitString encoded chunk",
2619 klass=self.__class__,
2620 decode_path=sub_decode_path,
2623 chunks.append(chunk)
2624 sub_offset += chunk.tlvlen
2625 vlen += chunk.tlvlen
2627 if len(chunks) == 0:
2630 klass=self.__class__,
2631 decode_path=decode_path,
2636 for chunk_i, chunk in enumerate(chunks[:-1]):
2637 if chunk.bit_len % 8 != 0:
2639 "BitString chunk is not multiple of 8 bits",
2640 klass=self.__class__,
2641 decode_path=decode_path + (str(chunk_i),),
2642 offset=chunk.offset,
2644 values.append(bytes(chunk))
2645 bit_len += chunk.bit_len
2646 chunk_last = chunks[-1]
2647 values.append(bytes(chunk_last))
2648 bit_len += chunk_last.bit_len
2649 obj = self.__class__(
2650 value=(bit_len, b"".join(values)),
2653 default=self.default,
2654 optional=self.optional,
2656 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2658 obj.lenindef = lenindef
2659 obj.ber_encoded = True
2660 return obj, (v[EOC_LEN:] if lenindef else v)
2662 klass=self.__class__,
2663 decode_path=decode_path,
2668 return pp_console_row(next(self.pps()))
2670 def pps(self, decode_path=()):
2674 bit_len, blob = self._value
2675 value = "%d bits" % bit_len
2676 if len(self.specs) > 0:
2677 blob = tuple(self.named)
2680 asn1_type_name=self.asn1_type_name,
2681 obj_name=self.__class__.__name__,
2682 decode_path=decode_path,
2685 optional=self.optional,
2686 default=self == self.default,
2687 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2688 expl=None if self._expl is None else tag_decode(self._expl),
2693 expl_offset=self.expl_offset if self.expled else None,
2694 expl_tlen=self.expl_tlen if self.expled else None,
2695 expl_llen=self.expl_llen if self.expled else None,
2696 expl_vlen=self.expl_vlen if self.expled else None,
2697 expl_lenindef=self.expl_lenindef,
2698 lenindef=self.lenindef,
2699 ber_encoded=self.ber_encoded,
2702 defined_by, defined = self.defined or (None, None)
2703 if defined_by is not None:
2705 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2707 for pp in self.pps_lenindef(decode_path):
2711 class OctetString(Obj):
2712 """``OCTET STRING`` binary string type
2714 >>> s = OctetString(b"hello world")
2715 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2716 >>> s == OctetString(b"hello world")
2721 >>> OctetString(b"hello", bounds=(4, 4))
2722 Traceback (most recent call last):
2723 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2724 >>> OctetString(b"hell", bounds=(4, 4))
2725 OCTET STRING 4 bytes 68656c6c
2729 Pay attention that OCTET STRING can be encoded both in primitive
2730 and constructed forms. Decoder always checks constructed form tag
2731 additionally to specified primitive one. If BER decoding is
2732 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2733 of DER restrictions.
2735 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2736 tag_default = tag_encode(4)
2737 asn1_type_name = "OCTET STRING"
2750 :param value: set the value. Either binary type, or
2751 :py:class:`pyderasn.OctetString` object
2752 :param bounds: set ``(MIN, MAX)`` value size constraint.
2753 (-inf, +inf) by default
2754 :param bytes impl: override default tag with ``IMPLICIT`` one
2755 :param bytes expl: override default tag with ``EXPLICIT`` one
2756 :param default: set default value. Type same as in ``value``
2757 :param bool optional: is object ``OPTIONAL`` in sequence
2759 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2761 self._bound_min, self._bound_max = getattr(
2765 ) if bounds is None else bounds
2766 if value is not None:
2767 self._value = self._value_sanitize(value)
2768 if default is not None:
2769 default = self._value_sanitize(default)
2770 self.default = self.__class__(
2775 if self._value is None:
2776 self._value = default
2778 tag_klass, _, tag_num = tag_decode(self.tag)
2779 self.tag_constructed = tag_encode(
2781 form=TagFormConstructed,
2785 def _value_sanitize(self, value):
2786 if isinstance(value, binary_type):
2788 elif issubclass(value.__class__, OctetString):
2789 value = value._value
2791 raise InvalidValueType((self.__class__, bytes))
2792 if not self._bound_min <= len(value) <= self._bound_max:
2793 raise BoundsError(self._bound_min, len(value), self._bound_max)
2798 return self._value is not None
2801 obj = self.__class__()
2802 obj._value = self._value
2803 obj._bound_min = self._bound_min
2804 obj._bound_max = self._bound_max
2806 obj._expl = self._expl
2807 obj.default = self.default
2808 obj.optional = self.optional
2809 obj.offset = self.offset
2810 obj.llen = self.llen
2811 obj.vlen = self.vlen
2812 obj.expl_lenindef = self.expl_lenindef
2813 obj.lenindef = self.lenindef
2814 obj.ber_encoded = self.ber_encoded
2817 def __bytes__(self):
2818 self._assert_ready()
2821 def __eq__(self, their):
2822 if isinstance(their, binary_type):
2823 return self._value == their
2824 if not issubclass(their.__class__, OctetString):
2827 self._value == their._value and
2828 self.tag == their.tag and
2829 self._expl == their._expl
2832 def __lt__(self, their):
2833 return self._value < their._value
2844 return self.__class__(
2847 (self._bound_min, self._bound_max)
2848 if bounds is None else bounds
2850 impl=self.tag if impl is None else impl,
2851 expl=self._expl if expl is None else expl,
2852 default=self.default if default is None else default,
2853 optional=self.optional if optional is None else optional,
2857 self._assert_ready()
2860 len_encode(len(self._value)),
2864 def _decode_chunk(self, lv, offset, decode_path):
2866 l, llen, v = len_decode(lv)
2867 except DecodeError as err:
2868 raise err.__class__(
2870 klass=self.__class__,
2871 decode_path=decode_path,
2875 raise NotEnoughData(
2876 "encoded length is longer than data",
2877 klass=self.__class__,
2878 decode_path=decode_path,
2881 v, tail = v[:l], v[l:]
2883 obj = self.__class__(
2885 bounds=(self._bound_min, self._bound_max),
2888 default=self.default,
2889 optional=self.optional,
2890 _decoded=(offset, llen, l),
2892 except DecodeError as err:
2895 klass=self.__class__,
2896 decode_path=decode_path,
2899 except BoundsError as err:
2902 klass=self.__class__,
2903 decode_path=decode_path,
2908 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2910 t, tlen, lv = tag_strip(tlv)
2911 except DecodeError as err:
2912 raise err.__class__(
2914 klass=self.__class__,
2915 decode_path=decode_path,
2921 return self._decode_chunk(lv, offset, decode_path)
2922 if t == self.tag_constructed:
2923 if not ctx.get("bered", False):
2925 "unallowed BER constructed encoding",
2926 klass=self.__class__,
2927 decode_path=decode_path,
2934 l, llen, v = len_decode(lv)
2935 except LenIndefForm:
2936 llen, l, v = 1, 0, lv[1:]
2938 except DecodeError as err:
2939 raise err.__class__(
2941 klass=self.__class__,
2942 decode_path=decode_path,
2946 raise NotEnoughData(
2947 "encoded length is longer than data",
2948 klass=self.__class__,
2949 decode_path=decode_path,
2953 sub_offset = offset + tlen + llen
2957 if v[:EOC_LEN].tobytes() == EOC:
2964 "chunk out of bounds",
2965 klass=self.__class__,
2966 decode_path=decode_path + (str(len(chunks) - 1),),
2967 offset=chunks[-1].offset,
2969 sub_decode_path = decode_path + (str(len(chunks)),)
2971 chunk, v_tail = OctetString().decode(
2974 decode_path=sub_decode_path,
2977 _ctx_immutable=False,
2981 "expected OctetString encoded chunk",
2982 klass=self.__class__,
2983 decode_path=sub_decode_path,
2986 chunks.append(chunk)
2987 sub_offset += chunk.tlvlen
2988 vlen += chunk.tlvlen
2991 obj = self.__class__(
2992 value=b"".join(bytes(chunk) for chunk in chunks),
2993 bounds=(self._bound_min, self._bound_max),
2996 default=self.default,
2997 optional=self.optional,
2998 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3000 except DecodeError as err:
3003 klass=self.__class__,
3004 decode_path=decode_path,
3007 except BoundsError as err:
3010 klass=self.__class__,
3011 decode_path=decode_path,
3014 obj.lenindef = lenindef
3015 obj.ber_encoded = True
3016 return obj, (v[EOC_LEN:] if lenindef else v)
3018 klass=self.__class__,
3019 decode_path=decode_path,
3024 return pp_console_row(next(self.pps()))
3026 def pps(self, decode_path=()):
3029 asn1_type_name=self.asn1_type_name,
3030 obj_name=self.__class__.__name__,
3031 decode_path=decode_path,
3032 value=("%d bytes" % len(self._value)) if self.ready else None,
3033 blob=self._value if self.ready else None,
3034 optional=self.optional,
3035 default=self == self.default,
3036 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3037 expl=None if self._expl is None else tag_decode(self._expl),
3042 expl_offset=self.expl_offset if self.expled else None,
3043 expl_tlen=self.expl_tlen if self.expled else None,
3044 expl_llen=self.expl_llen if self.expled else None,
3045 expl_vlen=self.expl_vlen if self.expled else None,
3046 expl_lenindef=self.expl_lenindef,
3047 lenindef=self.lenindef,
3048 ber_encoded=self.ber_encoded,
3051 defined_by, defined = self.defined or (None, None)
3052 if defined_by is not None:
3054 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3056 for pp in self.pps_lenindef(decode_path):
3061 """``NULL`` null object
3069 tag_default = tag_encode(5)
3070 asn1_type_name = "NULL"
3074 value=None, # unused, but Sequence passes it
3081 :param bytes impl: override default tag with ``IMPLICIT`` one
3082 :param bytes expl: override default tag with ``EXPLICIT`` one
3083 :param bool optional: is object ``OPTIONAL`` in sequence
3085 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3093 obj = self.__class__()
3095 obj._expl = self._expl
3096 obj.default = self.default
3097 obj.optional = self.optional
3098 obj.offset = self.offset
3099 obj.llen = self.llen
3100 obj.vlen = self.vlen
3101 obj.expl_lenindef = self.expl_lenindef
3102 obj.lenindef = self.lenindef
3103 obj.ber_encoded = self.ber_encoded
3106 def __eq__(self, their):
3107 if not issubclass(their.__class__, Null):
3110 self.tag == their.tag and
3111 self._expl == their._expl
3121 return self.__class__(
3122 impl=self.tag if impl is None else impl,
3123 expl=self._expl if expl is None else expl,
3124 optional=self.optional if optional is None else optional,
3128 return self.tag + len_encode(0)
3130 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3132 t, _, lv = tag_strip(tlv)
3133 except DecodeError as err:
3134 raise err.__class__(
3136 klass=self.__class__,
3137 decode_path=decode_path,
3142 klass=self.__class__,
3143 decode_path=decode_path,
3146 if tag_only: # pragma: no cover
3149 l, _, v = len_decode(lv)
3150 except DecodeError as err:
3151 raise err.__class__(
3153 klass=self.__class__,
3154 decode_path=decode_path,
3158 raise InvalidLength(
3159 "Null must have zero length",
3160 klass=self.__class__,
3161 decode_path=decode_path,
3164 obj = self.__class__(
3167 optional=self.optional,
3168 _decoded=(offset, 1, 0),
3173 return pp_console_row(next(self.pps()))
3175 def pps(self, decode_path=()):
3178 asn1_type_name=self.asn1_type_name,
3179 obj_name=self.__class__.__name__,
3180 decode_path=decode_path,
3181 optional=self.optional,
3182 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3183 expl=None if self._expl is None else tag_decode(self._expl),
3188 expl_offset=self.expl_offset if self.expled else None,
3189 expl_tlen=self.expl_tlen if self.expled else None,
3190 expl_llen=self.expl_llen if self.expled else None,
3191 expl_vlen=self.expl_vlen if self.expled else None,
3192 expl_lenindef=self.expl_lenindef,
3195 for pp in self.pps_lenindef(decode_path):
3199 class ObjectIdentifier(Obj):
3200 """``OBJECT IDENTIFIER`` OID type
3202 >>> oid = ObjectIdentifier((1, 2, 3))
3203 OBJECT IDENTIFIER 1.2.3
3204 >>> oid == ObjectIdentifier("1.2.3")
3210 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3211 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3213 >>> str(ObjectIdentifier((3, 1)))
3214 Traceback (most recent call last):
3215 pyderasn.InvalidOID: unacceptable first arc value
3217 __slots__ = ("defines",)
3218 tag_default = tag_encode(6)
3219 asn1_type_name = "OBJECT IDENTIFIER"
3232 :param value: set the value. Either tuples of integers,
3233 string of "."-concatenated integers, or
3234 :py:class:`pyderasn.ObjectIdentifier` object
3235 :param defines: sequence of tuples. Each tuple has two elements.
3236 First one is relative to current one decode
3237 path, aiming to the field defined by that OID.
3238 Read about relative path in
3239 :py:func:`pyderasn.abs_decode_path`. Second
3240 tuple element is ``{OID: pyderasn.Obj()}``
3241 dictionary, mapping between current OID value
3242 and structure applied to defined field.
3243 :ref:`Read about DEFINED BY <definedby>`
3244 :param bytes impl: override default tag with ``IMPLICIT`` one
3245 :param bytes expl: override default tag with ``EXPLICIT`` one
3246 :param default: set default value. Type same as in ``value``
3247 :param bool optional: is object ``OPTIONAL`` in sequence
3249 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3251 if value is not None:
3252 self._value = self._value_sanitize(value)
3253 if default is not None:
3254 default = self._value_sanitize(default)
3255 self.default = self.__class__(
3260 if self._value is None:
3261 self._value = default
3262 self.defines = defines
3264 def __add__(self, their):
3265 if isinstance(their, self.__class__):
3266 return self.__class__(self._value + their._value)
3267 if isinstance(their, tuple):
3268 return self.__class__(self._value + their)
3269 raise InvalidValueType((self.__class__, tuple))
3271 def _value_sanitize(self, value):
3272 if issubclass(value.__class__, ObjectIdentifier):
3274 if isinstance(value, string_types):
3276 value = tuple(int(arc) for arc in value.split("."))
3278 raise InvalidOID("unacceptable arcs values")
3279 if isinstance(value, tuple):
3281 raise InvalidOID("less than 2 arcs")
3282 first_arc = value[0]
3283 if first_arc in (0, 1):
3284 if not (0 <= value[1] <= 39):
3285 raise InvalidOID("second arc is too wide")
3286 elif first_arc == 2:
3289 raise InvalidOID("unacceptable first arc value")
3291 raise InvalidValueType((self.__class__, str, tuple))
3295 return self._value is not None
3298 obj = self.__class__()
3299 obj._value = self._value
3300 obj.defines = self.defines
3302 obj._expl = self._expl
3303 obj.default = self.default
3304 obj.optional = self.optional
3305 obj.offset = self.offset
3306 obj.llen = self.llen
3307 obj.vlen = self.vlen
3308 obj.expl_lenindef = self.expl_lenindef
3309 obj.lenindef = self.lenindef
3310 obj.ber_encoded = self.ber_encoded
3314 self._assert_ready()
3315 return iter(self._value)
3318 return ".".join(str(arc) for arc in self._value or ())
3321 self._assert_ready()
3324 bytes(self._expl or b"") +
3325 str(self._value).encode("ascii"),
3328 def __eq__(self, their):
3329 if isinstance(their, tuple):
3330 return self._value == their
3331 if not issubclass(their.__class__, ObjectIdentifier):
3334 self.tag == their.tag and
3335 self._expl == their._expl and
3336 self._value == their._value
3339 def __lt__(self, their):
3340 return self._value < their._value
3351 return self.__class__(
3353 defines=self.defines if defines is None else defines,
3354 impl=self.tag if impl is None else impl,
3355 expl=self._expl if expl is None else expl,
3356 default=self.default if default is None else default,
3357 optional=self.optional if optional is None else optional,
3361 self._assert_ready()
3363 first_value = value[1]
3364 first_arc = value[0]
3367 elif first_arc == 1:
3369 elif first_arc == 2:
3371 else: # pragma: no cover
3372 raise RuntimeError("invalid arc is stored")
3373 octets = [zero_ended_encode(first_value)]
3374 for arc in value[2:]:
3375 octets.append(zero_ended_encode(arc))
3376 v = b"".join(octets)
3377 return b"".join((self.tag, len_encode(len(v)), v))
3379 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3381 t, _, lv = tag_strip(tlv)
3382 except DecodeError as err:
3383 raise err.__class__(
3385 klass=self.__class__,
3386 decode_path=decode_path,
3391 klass=self.__class__,
3392 decode_path=decode_path,
3395 if tag_only: # pragma: no cover
3398 l, llen, v = len_decode(lv)
3399 except DecodeError as err:
3400 raise err.__class__(
3402 klass=self.__class__,
3403 decode_path=decode_path,
3407 raise NotEnoughData(
3408 "encoded length is longer than data",
3409 klass=self.__class__,
3410 decode_path=decode_path,
3414 raise NotEnoughData(
3416 klass=self.__class__,
3417 decode_path=decode_path,
3420 v, tail = v[:l], v[l:]
3427 octet = indexbytes(v, i)
3428 if i == 0 and octet == 0x80:
3429 if ctx.get("bered", False):
3432 raise DecodeError("non normalized arc encoding")
3433 arc = (arc << 7) | (octet & 0x7F)
3434 if octet & 0x80 == 0:
3442 klass=self.__class__,
3443 decode_path=decode_path,
3447 second_arc = arcs[0]
3448 if 0 <= second_arc <= 39:
3450 elif 40 <= second_arc <= 79:
3456 obj = self.__class__(
3457 value=tuple([first_arc, second_arc] + arcs[1:]),
3460 default=self.default,
3461 optional=self.optional,
3462 _decoded=(offset, llen, l),
3465 obj.ber_encoded = True
3469 return pp_console_row(next(self.pps()))
3471 def pps(self, decode_path=()):
3474 asn1_type_name=self.asn1_type_name,
3475 obj_name=self.__class__.__name__,
3476 decode_path=decode_path,
3477 value=str(self) if self.ready else None,
3478 optional=self.optional,
3479 default=self == self.default,
3480 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3481 expl=None if self._expl is None else tag_decode(self._expl),
3486 expl_offset=self.expl_offset if self.expled else None,
3487 expl_tlen=self.expl_tlen if self.expled else None,
3488 expl_llen=self.expl_llen if self.expled else None,
3489 expl_vlen=self.expl_vlen if self.expled else None,
3490 expl_lenindef=self.expl_lenindef,
3491 ber_encoded=self.ber_encoded,
3494 for pp in self.pps_lenindef(decode_path):
3498 class Enumerated(Integer):
3499 """``ENUMERATED`` integer type
3501 This type is identical to :py:class:`pyderasn.Integer`, but requires
3502 schema to be specified and does not accept values missing from it.
3505 tag_default = tag_encode(10)
3506 asn1_type_name = "ENUMERATED"
3517 bounds=None, # dummy argument, workability for Integer.decode
3519 super(Enumerated, self).__init__(
3520 value, bounds, impl, expl, default, optional, _specs, _decoded,
3522 if len(self.specs) == 0:
3523 raise ValueError("schema must be specified")
3525 def _value_sanitize(self, value):
3526 if isinstance(value, self.__class__):
3527 value = value._value
3528 elif isinstance(value, integer_types):
3529 for _value in itervalues(self.specs):
3534 "unknown integer value: %s" % value,
3535 klass=self.__class__,
3537 elif isinstance(value, string_types):
3538 value = self.specs.get(value)
3540 raise ObjUnknown("integer value: %s" % value)
3542 raise InvalidValueType((self.__class__, int, str))
3546 obj = self.__class__(_specs=self.specs)
3547 obj._value = self._value
3548 obj._bound_min = self._bound_min
3549 obj._bound_max = self._bound_max
3551 obj._expl = self._expl
3552 obj.default = self.default
3553 obj.optional = self.optional
3554 obj.offset = self.offset
3555 obj.llen = self.llen
3556 obj.vlen = self.vlen
3557 obj.expl_lenindef = self.expl_lenindef
3558 obj.lenindef = self.lenindef
3559 obj.ber_encoded = self.ber_encoded
3571 return self.__class__(
3573 impl=self.tag if impl is None else impl,
3574 expl=self._expl if expl is None else expl,
3575 default=self.default if default is None else default,
3576 optional=self.optional if optional is None else optional,
3581 def escape_control_unicode(c):
3582 if unicat(c).startswith("C"):
3583 c = repr(c).lstrip("u").strip("'")
3587 class CommonString(OctetString):
3588 """Common class for all strings
3590 Everything resembles :py:class:`pyderasn.OctetString`, except
3591 ability to deal with unicode text strings.
3593 >>> hexenc("привет мир".encode("utf-8"))
3594 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3595 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3597 >>> s = UTF8String("привет мир")
3598 UTF8String UTF8String привет мир
3600 'привет мир'
3601 >>> hexenc(bytes(s))
3602 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3604 >>> PrintableString("привет мир")
3605 Traceback (most recent call last):
3606 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3608 >>> BMPString("ада", bounds=(2, 2))
3609 Traceback (most recent call last):
3610 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3611 >>> s = BMPString("ад", bounds=(2, 2))
3614 >>> hexenc(bytes(s))
3622 * - :py:class:`pyderasn.UTF8String`
3624 * - :py:class:`pyderasn.NumericString`
3626 * - :py:class:`pyderasn.PrintableString`
3628 * - :py:class:`pyderasn.TeletexString`
3630 * - :py:class:`pyderasn.T61String`
3632 * - :py:class:`pyderasn.VideotexString`
3634 * - :py:class:`pyderasn.IA5String`
3636 * - :py:class:`pyderasn.GraphicString`
3638 * - :py:class:`pyderasn.VisibleString`
3640 * - :py:class:`pyderasn.ISO646String`
3642 * - :py:class:`pyderasn.GeneralString`
3644 * - :py:class:`pyderasn.UniversalString`
3646 * - :py:class:`pyderasn.BMPString`
3651 def _value_sanitize(self, value):
3653 value_decoded = None
3654 if isinstance(value, self.__class__):
3655 value_raw = value._value
3656 elif isinstance(value, text_type):
3657 value_decoded = value
3658 elif isinstance(value, binary_type):
3661 raise InvalidValueType((self.__class__, text_type, binary_type))
3664 value_decoded.encode(self.encoding)
3665 if value_raw is None else value_raw
3668 value_raw.decode(self.encoding)
3669 if value_decoded is None else value_decoded
3671 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3672 raise DecodeError(str(err))
3673 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3681 def __eq__(self, their):
3682 if isinstance(their, binary_type):
3683 return self._value == their
3684 if isinstance(their, text_type):
3685 return self._value == their.encode(self.encoding)
3686 if not isinstance(their, self.__class__):
3689 self._value == their._value and
3690 self.tag == their.tag and
3691 self._expl == their._expl
3694 def __unicode__(self):
3696 return self._value.decode(self.encoding)
3697 return text_type(self._value)
3700 return pp_console_row(next(self.pps(no_unicode=PY2)))
3702 def pps(self, decode_path=(), no_unicode=False):
3706 hexenc(bytes(self)) if no_unicode else
3707 "".join(escape_control_unicode(c) for c in self.__unicode__())
3711 asn1_type_name=self.asn1_type_name,
3712 obj_name=self.__class__.__name__,
3713 decode_path=decode_path,
3715 optional=self.optional,
3716 default=self == self.default,
3717 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3718 expl=None if self._expl is None else tag_decode(self._expl),
3723 expl_offset=self.expl_offset if self.expled else None,
3724 expl_tlen=self.expl_tlen if self.expled else None,
3725 expl_llen=self.expl_llen if self.expled else None,
3726 expl_vlen=self.expl_vlen if self.expled else None,
3727 expl_lenindef=self.expl_lenindef,
3728 ber_encoded=self.ber_encoded,
3731 for pp in self.pps_lenindef(decode_path):
3735 class UTF8String(CommonString):
3737 tag_default = tag_encode(12)
3739 asn1_type_name = "UTF8String"
3742 class AllowableCharsMixin(object):
3744 def allowable_chars(self):
3746 return self._allowable_chars
3747 return frozenset(six_unichr(c) for c in self._allowable_chars)
3750 class NumericString(AllowableCharsMixin, CommonString):
3753 Its value is properly sanitized: only ASCII digits with spaces can
3756 >>> NumericString().allowable_chars
3757 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3760 tag_default = tag_encode(18)
3762 asn1_type_name = "NumericString"
3763 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3765 def _value_sanitize(self, value):
3766 value = super(NumericString, self)._value_sanitize(value)
3767 if not frozenset(value) <= self._allowable_chars:
3768 raise DecodeError("non-numeric value")
3772 class PrintableString(AllowableCharsMixin, CommonString):
3775 Its value is properly sanitized: see X.680 41.4 table 10.
3777 >>> PrintableString().allowable_chars
3778 frozenset([' ', "'", ..., 'z'])
3781 tag_default = tag_encode(19)
3783 asn1_type_name = "PrintableString"
3784 _allowable_chars = frozenset(
3785 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
3787 _asterisk = frozenset("*".encode("ascii"))
3788 _ampersand = frozenset("&".encode("ascii"))
3799 allow_asterisk=False,
3800 allow_ampersand=False,
3803 :param allow_asterisk: allow asterisk character
3804 :param allow_ampersand: allow ampersand character
3807 self._allowable_chars |= self._asterisk
3809 self._allowable_chars |= self._ampersand
3810 super(PrintableString, self).__init__(
3811 value, bounds, impl, expl, default, optional, _decoded,
3814 def _value_sanitize(self, value):
3815 value = super(PrintableString, self)._value_sanitize(value)
3816 if not frozenset(value) <= self._allowable_chars:
3817 raise DecodeError("non-printable value")
3821 obj = super(PrintableString, self).copy()
3822 obj._allowable_chars = self._allowable_chars
3834 return self.__class__(
3837 (self._bound_min, self._bound_max)
3838 if bounds is None else bounds
3840 impl=self.tag if impl is None else impl,
3841 expl=self._expl if expl is None else expl,
3842 default=self.default if default is None else default,
3843 optional=self.optional if optional is None else optional,
3844 allow_asterisk=self._asterisk <= self._allowable_chars,
3845 allow_ampersand=self._ampersand <= self._allowable_chars,
3849 class TeletexString(CommonString):
3851 tag_default = tag_encode(20)
3853 asn1_type_name = "TeletexString"
3856 class T61String(TeletexString):
3858 asn1_type_name = "T61String"
3861 class VideotexString(CommonString):
3863 tag_default = tag_encode(21)
3864 encoding = "iso-8859-1"
3865 asn1_type_name = "VideotexString"
3868 class IA5String(CommonString):
3870 tag_default = tag_encode(22)
3872 asn1_type_name = "IA5"
3875 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
3876 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
3877 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
3880 class UTCTime(CommonString):
3881 """``UTCTime`` datetime type
3883 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3884 UTCTime UTCTime 2017-09-30T22:07:50
3890 datetime.datetime(2017, 9, 30, 22, 7, 50)
3891 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
3892 datetime.datetime(1957, 9, 30, 22, 7, 50)
3896 BER encoding is unsupported.
3899 tag_default = tag_encode(23)
3901 asn1_type_name = "UTCTime"
3911 bounds=None, # dummy argument, workability for OctetString.decode
3914 :param value: set the value. Either datetime type, or
3915 :py:class:`pyderasn.UTCTime` object
3916 :param bytes impl: override default tag with ``IMPLICIT`` one
3917 :param bytes expl: override default tag with ``EXPLICIT`` one
3918 :param default: set default value. Type same as in ``value``
3919 :param bool optional: is object ``OPTIONAL`` in sequence
3921 super(UTCTime, self).__init__(
3922 None, None, impl, expl, default, optional, _decoded,
3925 if value is not None:
3926 self._value = self._value_sanitize(value)
3927 if default is not None:
3928 default = self._value_sanitize(default)
3929 self.default = self.__class__(
3934 if self._value is None:
3935 self._value = default
3937 def _strptime(self, value):
3938 # datetime.strptime's format: %y%m%d%H%M%SZ
3939 if len(value) != LEN_YYMMDDHHMMSSZ:
3940 raise ValueError("invalid UTCTime length")
3941 if value[-1] != "Z":
3942 raise ValueError("non UTC timezone")
3944 2000 + int(value[:2]), # %y
3945 int(value[2:4]), # %m
3946 int(value[4:6]), # %d
3947 int(value[6:8]), # %H
3948 int(value[8:10]), # %M
3949 int(value[10:12]), # %S
3952 def _value_sanitize(self, value):
3953 if isinstance(value, binary_type):
3955 value_decoded = value.decode("ascii")
3956 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3957 raise DecodeError("invalid UTCTime encoding: %r" % err)
3959 self._strptime(value_decoded)
3960 except (TypeError, ValueError) as err:
3961 raise DecodeError("invalid UTCTime format: %r" % err)
3963 if isinstance(value, self.__class__):
3965 if isinstance(value, datetime):
3966 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
3967 raise InvalidValueType((self.__class__, datetime))
3969 def __eq__(self, their):
3970 if isinstance(their, binary_type):
3971 return self._value == their
3972 if isinstance(their, datetime):
3973 return self.todatetime() == their
3974 if not isinstance(their, self.__class__):
3977 self._value == their._value and
3978 self.tag == their.tag and
3979 self._expl == their._expl
3982 def todatetime(self):
3983 """Convert to datetime
3987 Pay attention that UTCTime can not hold full year, so all years
3988 having < 50 years are treated as 20xx, 19xx otherwise, according
3989 to X.509 recomendation.
3991 value = self._strptime(self._value.decode("ascii"))
3992 year = value.year % 100
3994 year=(2000 + year) if year < 50 else (1900 + year),
3998 minute=value.minute,
3999 second=value.second,
4003 return pp_console_row(next(self.pps()))
4005 def pps(self, decode_path=()):
4008 asn1_type_name=self.asn1_type_name,
4009 obj_name=self.__class__.__name__,
4010 decode_path=decode_path,
4011 value=self.todatetime().isoformat() if self.ready else None,
4012 optional=self.optional,
4013 default=self == self.default,
4014 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4015 expl=None if self._expl is None else tag_decode(self._expl),
4020 expl_offset=self.expl_offset if self.expled else None,
4021 expl_tlen=self.expl_tlen if self.expled else None,
4022 expl_llen=self.expl_llen if self.expled else None,
4023 expl_vlen=self.expl_vlen if self.expled else None,
4024 expl_lenindef=self.expl_lenindef,
4025 ber_encoded=self.ber_encoded,
4028 for pp in self.pps_lenindef(decode_path):
4032 class GeneralizedTime(UTCTime):
4033 """``GeneralizedTime`` datetime type
4035 This type is similar to :py:class:`pyderasn.UTCTime`.
4037 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4038 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4040 '20170930220750.000123Z'
4041 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4042 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4046 BER encoding is unsupported.
4050 Only microsecond fractions are supported.
4051 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4052 higher precision values.
4055 tag_default = tag_encode(24)
4056 asn1_type_name = "GeneralizedTime"
4058 def _strptime(self, value):
4060 if l == LEN_YYYYMMDDHHMMSSZ:
4061 # datetime.strptime's format: %y%m%d%H%M%SZ
4062 if value[-1] != "Z":
4063 raise ValueError("non UTC timezone")
4065 int(value[:4]), # %Y
4066 int(value[4:6]), # %m
4067 int(value[6:8]), # %d
4068 int(value[8:10]), # %H
4069 int(value[10:12]), # %M
4070 int(value[12:14]), # %S
4072 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4073 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4074 if value[-1] != "Z":
4075 raise ValueError("non UTC timezone")
4076 if value[14] != ".":
4077 raise ValueError("no fractions separator")
4080 raise ValueError("trailing zero")
4083 raise ValueError("only microsecond fractions are supported")
4084 us = int(us + ("0" * (6 - us_len)))
4086 int(value[:4]), # %Y
4087 int(value[4:6]), # %m
4088 int(value[6:8]), # %d
4089 int(value[8:10]), # %H
4090 int(value[10:12]), # %M
4091 int(value[12:14]), # %S
4095 raise ValueError("invalid GeneralizedTime length")
4097 def _value_sanitize(self, value):
4098 if isinstance(value, binary_type):
4100 value_decoded = value.decode("ascii")
4101 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4102 raise DecodeError("invalid GeneralizedTime encoding: %r" % err)
4104 self._strptime(value_decoded)
4105 except (TypeError, ValueError) as err:
4107 "invalid GeneralizedTime format: %r" % err,
4108 klass=self.__class__,
4111 if isinstance(value, self.__class__):
4113 if isinstance(value, datetime):
4114 encoded = value.strftime("%Y%m%d%H%M%S")
4115 if value.microsecond > 0:
4116 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
4117 return (encoded + "Z").encode("ascii")
4118 raise InvalidValueType((self.__class__, datetime))
4120 def todatetime(self):
4121 return self._strptime(self._value.decode("ascii"))
4124 class GraphicString(CommonString):
4126 tag_default = tag_encode(25)
4127 encoding = "iso-8859-1"
4128 asn1_type_name = "GraphicString"
4131 class VisibleString(CommonString):
4133 tag_default = tag_encode(26)
4135 asn1_type_name = "VisibleString"
4138 class ISO646String(VisibleString):
4140 asn1_type_name = "ISO646String"
4143 class GeneralString(CommonString):
4145 tag_default = tag_encode(27)
4146 encoding = "iso-8859-1"
4147 asn1_type_name = "GeneralString"
4150 class UniversalString(CommonString):
4152 tag_default = tag_encode(28)
4153 encoding = "utf-32-be"
4154 asn1_type_name = "UniversalString"
4157 class BMPString(CommonString):
4159 tag_default = tag_encode(30)
4160 encoding = "utf-16-be"
4161 asn1_type_name = "BMPString"
4165 """``CHOICE`` special type
4169 class GeneralName(Choice):
4171 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4172 ("dNSName", IA5String(impl=tag_ctxp(2))),
4175 >>> gn = GeneralName()
4177 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4178 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4179 >>> gn["dNSName"] = IA5String("bar.baz")
4180 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4181 >>> gn["rfc822Name"]
4184 [2] IA5String IA5 bar.baz
4187 >>> gn.value == gn["dNSName"]
4190 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4192 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4193 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4195 __slots__ = ("specs",)
4197 asn1_type_name = "CHOICE"
4210 :param value: set the value. Either ``(choice, value)`` tuple, or
4211 :py:class:`pyderasn.Choice` object
4212 :param bytes impl: can not be set, do **not** use it
4213 :param bytes expl: override default tag with ``EXPLICIT`` one
4214 :param default: set default value. Type same as in ``value``
4215 :param bool optional: is object ``OPTIONAL`` in sequence
4217 if impl is not None:
4218 raise ValueError("no implicit tag allowed for CHOICE")
4219 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4221 schema = getattr(self, "schema", ())
4222 if len(schema) == 0:
4223 raise ValueError("schema must be specified")
4225 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4228 if value is not None:
4229 self._value = self._value_sanitize(value)
4230 if default is not None:
4231 default_value = self._value_sanitize(default)
4232 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4233 default_obj.specs = self.specs
4234 default_obj._value = default_value
4235 self.default = default_obj
4237 self._value = default_obj.copy()._value
4239 def _value_sanitize(self, value):
4240 if isinstance(value, tuple) and len(value) == 2:
4242 spec = self.specs.get(choice)
4244 raise ObjUnknown(choice)
4245 if not isinstance(obj, spec.__class__):
4246 raise InvalidValueType((spec,))
4247 return (choice, spec(obj))
4248 if isinstance(value, self.__class__):
4250 raise InvalidValueType((self.__class__, tuple))
4254 return self._value is not None and self._value[1].ready
4258 return self.expl_lenindef or (
4259 (self._value is not None) and
4260 self._value[1].bered
4264 obj = self.__class__(schema=self.specs)
4265 obj._expl = self._expl
4266 obj.default = self.default
4267 obj.optional = self.optional
4268 obj.offset = self.offset
4269 obj.llen = self.llen
4270 obj.vlen = self.vlen
4271 obj.expl_lenindef = self.expl_lenindef
4272 obj.lenindef = self.lenindef
4273 obj.ber_encoded = self.ber_encoded
4275 if value is not None:
4276 obj._value = (value[0], value[1].copy())
4279 def __eq__(self, their):
4280 if isinstance(their, tuple) and len(their) == 2:
4281 return self._value == their
4282 if not isinstance(their, self.__class__):
4285 self.specs == their.specs and
4286 self._value == their._value
4296 return self.__class__(
4299 expl=self._expl if expl is None else expl,
4300 default=self.default if default is None else default,
4301 optional=self.optional if optional is None else optional,
4306 self._assert_ready()
4307 return self._value[0]
4311 self._assert_ready()
4312 return self._value[1]
4314 def __getitem__(self, key):
4315 if key not in self.specs:
4316 raise ObjUnknown(key)
4317 if self._value is None:
4319 choice, value = self._value
4324 def __setitem__(self, key, value):
4325 spec = self.specs.get(key)
4327 raise ObjUnknown(key)
4328 if not isinstance(value, spec.__class__):
4329 raise InvalidValueType((spec.__class__,))
4330 self._value = (key, spec(value))
4338 return self._value[1].decoded if self.ready else False
4341 self._assert_ready()
4342 return self._value[1].encode()
4344 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4345 for choice, spec in iteritems(self.specs):
4346 sub_decode_path = decode_path + (choice,)
4352 decode_path=sub_decode_path,
4355 _ctx_immutable=False,
4362 klass=self.__class__,
4363 decode_path=decode_path,
4366 if tag_only: # pragma: no cover
4368 value, tail = spec.decode(
4372 decode_path=sub_decode_path,
4374 _ctx_immutable=False,
4376 obj = self.__class__(
4379 default=self.default,
4380 optional=self.optional,
4381 _decoded=(offset, 0, value.fulllen),
4383 obj._value = (choice, value)
4387 value = pp_console_row(next(self.pps()))
4389 value = "%s[%r]" % (value, self.value)
4392 def pps(self, decode_path=()):
4395 asn1_type_name=self.asn1_type_name,
4396 obj_name=self.__class__.__name__,
4397 decode_path=decode_path,
4398 value=self.choice if self.ready else None,
4399 optional=self.optional,
4400 default=self == self.default,
4401 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4402 expl=None if self._expl is None else tag_decode(self._expl),
4407 expl_lenindef=self.expl_lenindef,
4411 yield self.value.pps(decode_path=decode_path + (self.choice,))
4412 for pp in self.pps_lenindef(decode_path):
4416 class PrimitiveTypes(Choice):
4417 """Predefined ``CHOICE`` for all generic primitive types
4419 It could be useful for general decoding of some unspecified values:
4421 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4422 OCTET STRING 3 bytes 666f6f
4423 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4427 schema = tuple((klass.__name__, klass()) for klass in (
4452 """``ANY`` special type
4454 >>> Any(Integer(-123))
4456 >>> a = Any(OctetString(b"hello world").encode())
4457 ANY 040b68656c6c6f20776f726c64
4458 >>> hexenc(bytes(a))
4459 b'0x040x0bhello world'
4461 __slots__ = ("defined",)
4462 tag_default = tag_encode(0)
4463 asn1_type_name = "ANY"
4473 :param value: set the value. Either any kind of pyderasn's
4474 **ready** object, or bytes. Pay attention that
4475 **no** validation is performed is raw binary value
4477 :param bytes expl: override default tag with ``EXPLICIT`` one
4478 :param bool optional: is object ``OPTIONAL`` in sequence
4480 super(Any, self).__init__(None, expl, None, optional, _decoded)
4481 self._value = None if value is None else self._value_sanitize(value)
4484 def _value_sanitize(self, value):
4485 if isinstance(value, binary_type):
4487 if isinstance(value, self.__class__):
4489 if isinstance(value, Obj):
4490 return value.encode()
4491 raise InvalidValueType((self.__class__, Obj, binary_type))
4495 return self._value is not None
4499 if self.expl_lenindef or self.lenindef:
4501 if self.defined is None:
4503 return self.defined[1].bered
4506 obj = self.__class__()
4507 obj._value = self._value
4509 obj._expl = self._expl
4510 obj.optional = self.optional
4511 obj.offset = self.offset
4512 obj.llen = self.llen
4513 obj.vlen = self.vlen
4514 obj.expl_lenindef = self.expl_lenindef
4515 obj.lenindef = self.lenindef
4516 obj.ber_encoded = self.ber_encoded
4519 def __eq__(self, their):
4520 if isinstance(their, binary_type):
4521 return self._value == their
4522 if issubclass(their.__class__, Any):
4523 return self._value == their._value
4532 return self.__class__(
4534 expl=self._expl if expl is None else expl,
4535 optional=self.optional if optional is None else optional,
4538 def __bytes__(self):
4539 self._assert_ready()
4547 self._assert_ready()
4550 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4552 t, tlen, lv = tag_strip(tlv)
4553 except DecodeError as err:
4554 raise err.__class__(
4556 klass=self.__class__,
4557 decode_path=decode_path,
4561 l, llen, v = len_decode(lv)
4562 except LenIndefForm as err:
4563 if not ctx.get("bered", False):
4564 raise err.__class__(
4566 klass=self.__class__,
4567 decode_path=decode_path,
4570 llen, vlen, v = 1, 0, lv[1:]
4571 sub_offset = offset + tlen + llen
4573 while v[:EOC_LEN].tobytes() != EOC:
4574 chunk, v = Any().decode(
4577 decode_path=decode_path + (str(chunk_i),),
4580 _ctx_immutable=False,
4582 vlen += chunk.tlvlen
4583 sub_offset += chunk.tlvlen
4585 tlvlen = tlen + llen + vlen + EOC_LEN
4586 obj = self.__class__(
4587 value=tlv[:tlvlen].tobytes(),
4589 optional=self.optional,
4590 _decoded=(offset, 0, tlvlen),
4593 obj.tag = t.tobytes()
4594 return obj, v[EOC_LEN:]
4595 except DecodeError as err:
4596 raise err.__class__(
4598 klass=self.__class__,
4599 decode_path=decode_path,
4603 raise NotEnoughData(
4604 "encoded length is longer than data",
4605 klass=self.__class__,
4606 decode_path=decode_path,
4609 tlvlen = tlen + llen + l
4610 v, tail = tlv[:tlvlen], v[l:]
4611 obj = self.__class__(
4614 optional=self.optional,
4615 _decoded=(offset, 0, tlvlen),
4617 obj.tag = t.tobytes()
4621 return pp_console_row(next(self.pps()))
4623 def pps(self, decode_path=()):
4626 asn1_type_name=self.asn1_type_name,
4627 obj_name=self.__class__.__name__,
4628 decode_path=decode_path,
4629 blob=self._value if self.ready else None,
4630 optional=self.optional,
4631 default=self == self.default,
4632 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4633 expl=None if self._expl is None else tag_decode(self._expl),
4638 expl_offset=self.expl_offset if self.expled else None,
4639 expl_tlen=self.expl_tlen if self.expled else None,
4640 expl_llen=self.expl_llen if self.expled else None,
4641 expl_vlen=self.expl_vlen if self.expled else None,
4642 expl_lenindef=self.expl_lenindef,
4643 lenindef=self.lenindef,
4646 defined_by, defined = self.defined or (None, None)
4647 if defined_by is not None:
4649 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4651 for pp in self.pps_lenindef(decode_path):
4655 ########################################################################
4656 # ASN.1 constructed types
4657 ########################################################################
4659 def get_def_by_path(defines_by_path, sub_decode_path):
4660 """Get define by decode path
4662 for path, define in defines_by_path:
4663 if len(path) != len(sub_decode_path):
4665 for p1, p2 in zip(path, sub_decode_path):
4666 if (p1 != any) and (p1 != p2):
4672 def abs_decode_path(decode_path, rel_path):
4673 """Create an absolute decode path from current and relative ones
4675 :param decode_path: current decode path, starting point. Tuple of strings
4676 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4677 If first tuple's element is "/", then treat it as
4678 an absolute path, ignoring ``decode_path`` as
4679 starting point. Also this tuple can contain ".."
4680 elements, stripping the leading element from
4683 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4684 ("foo", "bar", "baz", "whatever")
4685 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4687 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4690 if rel_path[0] == "/":
4692 if rel_path[0] == "..":
4693 return abs_decode_path(decode_path[:-1], rel_path[1:])
4694 return decode_path + rel_path
4697 class Sequence(Obj):
4698 """``SEQUENCE`` structure type
4700 You have to make specification of sequence::
4702 class Extension(Sequence):
4704 ("extnID", ObjectIdentifier()),
4705 ("critical", Boolean(default=False)),
4706 ("extnValue", OctetString()),
4709 Then, you can work with it as with dictionary.
4711 >>> ext = Extension()
4712 >>> Extension().specs
4714 ('extnID', OBJECT IDENTIFIER),
4715 ('critical', BOOLEAN False OPTIONAL DEFAULT),
4716 ('extnValue', OCTET STRING),
4718 >>> ext["extnID"] = "1.2.3"
4719 Traceback (most recent call last):
4720 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
4721 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
4723 You can determine if sequence is ready to be encoded:
4728 Traceback (most recent call last):
4729 pyderasn.ObjNotReady: object is not ready: extnValue
4730 >>> ext["extnValue"] = OctetString(b"foobar")
4734 Value you want to assign, must have the same **type** as in
4735 corresponding specification, but it can have different tags,
4736 optional/default attributes -- they will be taken from specification
4739 class TBSCertificate(Sequence):
4741 ("version", Version(expl=tag_ctxc(0), default="v1")),
4744 >>> tbs = TBSCertificate()
4745 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
4747 Assign ``None`` to remove value from sequence.
4749 You can set values in Sequence during its initialization:
4751 >>> AlgorithmIdentifier((
4752 ("algorithm", ObjectIdentifier("1.2.3")),
4753 ("parameters", Any(Null()))
4755 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
4757 You can determine if value exists/set in the sequence and take its value:
4759 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
4762 OBJECT IDENTIFIER 1.2.3
4764 But pay attention that if value has default, then it won't be (not
4765 in) in the sequence (because ``DEFAULT`` must not be encoded in
4766 DER), but you can read its value:
4768 >>> "critical" in ext, ext["critical"]
4769 (False, BOOLEAN False)
4770 >>> ext["critical"] = Boolean(True)
4771 >>> "critical" in ext, ext["critical"]
4772 (True, BOOLEAN True)
4774 All defaulted values are always optional.
4776 .. _allow_default_values_ctx:
4778 DER prohibits default value encoding and will raise an error if
4779 default value is unexpectedly met during decode.
4780 If :ref:`bered <bered_ctx>` context option is set, then no error
4781 will be raised, but ``bered`` attribute set. You can disable strict
4782 defaulted values existence validation by setting
4783 ``"allow_default_values": True`` :ref:`context <ctx>` option.
4785 Two sequences are equal if they have equal specification (schema),
4786 implicit/explicit tagging and the same values.
4788 __slots__ = ("specs",)
4789 tag_default = tag_encode(form=TagFormConstructed, num=16)
4790 asn1_type_name = "SEQUENCE"
4802 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
4804 schema = getattr(self, "schema", ())
4806 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4809 if value is not None:
4810 if issubclass(value.__class__, Sequence):
4811 self._value = value._value
4812 elif hasattr(value, "__iter__"):
4813 for seq_key, seq_value in value:
4814 self[seq_key] = seq_value
4816 raise InvalidValueType((Sequence,))
4817 if default is not None:
4818 if not issubclass(default.__class__, Sequence):
4819 raise InvalidValueType((Sequence,))
4820 default_value = default._value
4821 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4822 default_obj.specs = self.specs
4823 default_obj._value = default_value
4824 self.default = default_obj
4826 self._value = default_obj.copy()._value
4830 for name, spec in iteritems(self.specs):
4831 value = self._value.get(name)
4842 if self.expl_lenindef or self.lenindef or self.ber_encoded:
4844 return any(value.bered for value in itervalues(self._value))
4847 obj = self.__class__(schema=self.specs)
4849 obj._expl = self._expl
4850 obj.default = self.default
4851 obj.optional = self.optional
4852 obj.offset = self.offset
4853 obj.llen = self.llen
4854 obj.vlen = self.vlen
4855 obj.expl_lenindef = self.expl_lenindef
4856 obj.lenindef = self.lenindef
4857 obj.ber_encoded = self.ber_encoded
4858 obj._value = {k: v.copy() for k, v in iteritems(self._value)}
4861 def __eq__(self, their):
4862 if not isinstance(their, self.__class__):
4865 self.specs == their.specs and
4866 self.tag == their.tag and
4867 self._expl == their._expl and
4868 self._value == their._value
4879 return self.__class__(
4882 impl=self.tag if impl is None else impl,
4883 expl=self._expl if expl is None else expl,
4884 default=self.default if default is None else default,
4885 optional=self.optional if optional is None else optional,
4888 def __contains__(self, key):
4889 return key in self._value
4891 def __setitem__(self, key, value):
4892 spec = self.specs.get(key)
4894 raise ObjUnknown(key)
4896 self._value.pop(key, None)
4898 if not isinstance(value, spec.__class__):
4899 raise InvalidValueType((spec.__class__,))
4900 value = spec(value=value)
4901 if spec.default is not None and value == spec.default:
4902 self._value.pop(key, None)
4904 self._value[key] = value
4906 def __getitem__(self, key):
4907 value = self._value.get(key)
4908 if value is not None:
4910 spec = self.specs.get(key)
4912 raise ObjUnknown(key)
4913 if spec.default is not None:
4917 def _encoded_values(self):
4919 for name, spec in iteritems(self.specs):
4920 value = self._value.get(name)
4924 raise ObjNotReady(name)
4925 raws.append(value.encode())
4929 v = b"".join(self._encoded_values())
4930 return b"".join((self.tag, len_encode(len(v)), v))
4932 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4934 t, tlen, lv = tag_strip(tlv)
4935 except DecodeError as err:
4936 raise err.__class__(
4938 klass=self.__class__,
4939 decode_path=decode_path,
4944 klass=self.__class__,
4945 decode_path=decode_path,
4948 if tag_only: # pragma: no cover
4951 ctx_bered = ctx.get("bered", False)
4953 l, llen, v = len_decode(lv)
4954 except LenIndefForm as err:
4956 raise err.__class__(
4958 klass=self.__class__,
4959 decode_path=decode_path,
4962 l, llen, v = 0, 1, lv[1:]
4964 except DecodeError as err:
4965 raise err.__class__(
4967 klass=self.__class__,
4968 decode_path=decode_path,
4972 raise NotEnoughData(
4973 "encoded length is longer than data",
4974 klass=self.__class__,
4975 decode_path=decode_path,
4979 v, tail = v[:l], v[l:]
4981 sub_offset = offset + tlen + llen
4984 ctx_allow_default_values = ctx.get("allow_default_values", False)
4985 for name, spec in iteritems(self.specs):
4986 if spec.optional and (
4987 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
4991 sub_decode_path = decode_path + (name,)
4993 value, v_tail = spec.decode(
4997 decode_path=sub_decode_path,
4999 _ctx_immutable=False,
5001 except TagMismatch as err:
5002 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5006 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5007 if defined is not None:
5008 defined_by, defined_spec = defined
5009 if issubclass(value.__class__, SequenceOf):
5010 for i, _value in enumerate(value):
5011 sub_sub_decode_path = sub_decode_path + (
5013 DecodePathDefBy(defined_by),
5015 defined_value, defined_tail = defined_spec.decode(
5016 memoryview(bytes(_value)),
5018 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5019 if value.expled else (value.tlen + value.llen)
5022 decode_path=sub_sub_decode_path,
5024 _ctx_immutable=False,
5026 if len(defined_tail) > 0:
5029 klass=self.__class__,
5030 decode_path=sub_sub_decode_path,
5033 _value.defined = (defined_by, defined_value)
5035 defined_value, defined_tail = defined_spec.decode(
5036 memoryview(bytes(value)),
5038 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5039 if value.expled else (value.tlen + value.llen)
5042 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5044 _ctx_immutable=False,
5046 if len(defined_tail) > 0:
5049 klass=self.__class__,
5050 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5053 value.defined = (defined_by, defined_value)
5055 value_len = value.fulllen
5057 sub_offset += value_len
5059 if spec.default is not None and value == spec.default:
5060 if ctx_bered or ctx_allow_default_values:
5064 "DEFAULT value met",
5065 klass=self.__class__,
5066 decode_path=sub_decode_path,
5069 values[name] = value
5071 spec_defines = getattr(spec, "defines", ())
5072 if len(spec_defines) == 0:
5073 defines_by_path = ctx.get("defines_by_path", ())
5074 if len(defines_by_path) > 0:
5075 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5076 if spec_defines is not None and len(spec_defines) > 0:
5077 for rel_path, schema in spec_defines:
5078 defined = schema.get(value, None)
5079 if defined is not None:
5080 ctx.setdefault("_defines", []).append((
5081 abs_decode_path(sub_decode_path[:-1], rel_path),
5085 if v[:EOC_LEN].tobytes() != EOC:
5088 klass=self.__class__,
5089 decode_path=decode_path,
5097 klass=self.__class__,
5098 decode_path=decode_path,
5101 obj = self.__class__(
5105 default=self.default,
5106 optional=self.optional,
5107 _decoded=(offset, llen, vlen),
5110 obj.lenindef = lenindef
5111 obj.ber_encoded = ber_encoded
5115 value = pp_console_row(next(self.pps()))
5117 for name in self.specs:
5118 _value = self._value.get(name)
5121 cols.append("%s: %s" % (name, repr(_value)))
5122 return "%s[%s]" % (value, "; ".join(cols))
5124 def pps(self, decode_path=()):
5127 asn1_type_name=self.asn1_type_name,
5128 obj_name=self.__class__.__name__,
5129 decode_path=decode_path,
5130 optional=self.optional,
5131 default=self == self.default,
5132 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5133 expl=None if self._expl is None else tag_decode(self._expl),
5138 expl_offset=self.expl_offset if self.expled else None,
5139 expl_tlen=self.expl_tlen if self.expled else None,
5140 expl_llen=self.expl_llen if self.expled else None,
5141 expl_vlen=self.expl_vlen if self.expled else None,
5142 expl_lenindef=self.expl_lenindef,
5143 lenindef=self.lenindef,
5144 ber_encoded=self.ber_encoded,
5147 for name in self.specs:
5148 value = self._value.get(name)
5151 yield value.pps(decode_path=decode_path + (name,))
5152 for pp in self.pps_lenindef(decode_path):
5156 class Set(Sequence):
5157 """``SET`` structure type
5159 Its usage is identical to :py:class:`pyderasn.Sequence`.
5161 .. _allow_unordered_set_ctx:
5163 DER prohibits unordered values encoding and will raise an error
5164 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5165 then no error will occure. Also you can disable strict values
5166 ordering check by setting ``"allow_unordered_set": True``
5167 :ref:`context <ctx>` option.
5170 tag_default = tag_encode(form=TagFormConstructed, num=17)
5171 asn1_type_name = "SET"
5174 raws = self._encoded_values()
5177 return b"".join((self.tag, len_encode(len(v)), v))
5179 def _specs_items(self):
5180 return iteritems(self.specs)
5182 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5184 t, tlen, lv = tag_strip(tlv)
5185 except DecodeError as err:
5186 raise err.__class__(
5188 klass=self.__class__,
5189 decode_path=decode_path,
5194 klass=self.__class__,
5195 decode_path=decode_path,
5201 ctx_bered = ctx.get("bered", False)
5203 l, llen, v = len_decode(lv)
5204 except LenIndefForm as err:
5206 raise err.__class__(
5208 klass=self.__class__,
5209 decode_path=decode_path,
5212 l, llen, v = 0, 1, lv[1:]
5214 except DecodeError as err:
5215 raise err.__class__(
5217 klass=self.__class__,
5218 decode_path=decode_path,
5222 raise NotEnoughData(
5223 "encoded length is longer than data",
5224 klass=self.__class__,
5228 v, tail = v[:l], v[l:]
5230 sub_offset = offset + tlen + llen
5233 ctx_allow_default_values = ctx.get("allow_default_values", False)
5234 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5235 value_prev = memoryview(v[:0])
5238 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5240 for name, spec in self._specs_items():
5241 sub_decode_path = decode_path + (name,)
5247 decode_path=sub_decode_path,
5250 _ctx_immutable=False,
5257 klass=self.__class__,
5258 decode_path=decode_path,
5261 value, v_tail = spec.decode(
5265 decode_path=sub_decode_path,
5267 _ctx_immutable=False,
5269 value_len = value.fulllen
5270 if value_prev.tobytes() > v[:value_len].tobytes():
5271 if ctx_bered or ctx_allow_unordered_set:
5275 "unordered " + self.asn1_type_name,
5276 klass=self.__class__,
5277 decode_path=sub_decode_path,
5280 if spec.default is None or value != spec.default:
5282 elif ctx_bered or ctx_allow_default_values:
5286 "DEFAULT value met",
5287 klass=self.__class__,
5288 decode_path=sub_decode_path,
5291 values[name] = value
5292 value_prev = v[:value_len]
5293 sub_offset += value_len
5296 obj = self.__class__(
5300 default=self.default,
5301 optional=self.optional,
5302 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5305 if v[:EOC_LEN].tobytes() != EOC:
5308 klass=self.__class__,
5309 decode_path=decode_path,
5317 "not all values are ready",
5318 klass=self.__class__,
5319 decode_path=decode_path,
5322 obj.ber_encoded = ber_encoded
5326 class SequenceOf(Obj):
5327 """``SEQUENCE OF`` sequence type
5329 For that kind of type you must specify the object it will carry on
5330 (bounds are for example here, not required)::
5332 class Ints(SequenceOf):
5337 >>> ints.append(Integer(123))
5338 >>> ints.append(Integer(234))
5340 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5341 >>> [int(i) for i in ints]
5343 >>> ints.append(Integer(345))
5344 Traceback (most recent call last):
5345 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5348 >>> ints[1] = Integer(345)
5350 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5352 Also you can initialize sequence with preinitialized values:
5354 >>> ints = Ints([Integer(123), Integer(234)])
5356 __slots__ = ("spec", "_bound_min", "_bound_max")
5357 tag_default = tag_encode(form=TagFormConstructed, num=16)
5358 asn1_type_name = "SEQUENCE OF"
5371 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5373 schema = getattr(self, "schema", None)
5375 raise ValueError("schema must be specified")
5377 self._bound_min, self._bound_max = getattr(
5381 ) if bounds is None else bounds
5383 if value is not None:
5384 self._value = self._value_sanitize(value)
5385 if default is not None:
5386 default_value = self._value_sanitize(default)
5387 default_obj = self.__class__(
5392 default_obj._value = default_value
5393 self.default = default_obj
5395 self._value = default_obj.copy()._value
5397 def _value_sanitize(self, value):
5398 if issubclass(value.__class__, SequenceOf):
5399 value = value._value
5400 elif hasattr(value, "__iter__"):
5403 raise InvalidValueType((self.__class__, iter))
5404 if not self._bound_min <= len(value) <= self._bound_max:
5405 raise BoundsError(self._bound_min, len(value), self._bound_max)
5407 if not isinstance(v, self.spec.__class__):
5408 raise InvalidValueType((self.spec.__class__,))
5413 return all(v.ready for v in self._value)
5417 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5419 return any(v.bered for v in self._value)
5422 obj = self.__class__(schema=self.spec)
5423 obj._bound_min = self._bound_min
5424 obj._bound_max = self._bound_max
5426 obj._expl = self._expl
5427 obj.default = self.default
5428 obj.optional = self.optional
5429 obj.offset = self.offset
5430 obj.llen = self.llen
5431 obj.vlen = self.vlen
5432 obj.expl_lenindef = self.expl_lenindef
5433 obj.lenindef = self.lenindef
5434 obj.ber_encoded = self.ber_encoded
5435 obj._value = [v.copy() for v in self._value]
5438 def __eq__(self, their):
5439 if isinstance(their, self.__class__):
5441 self.spec == their.spec and
5442 self.tag == their.tag and
5443 self._expl == their._expl and
5444 self._value == their._value
5446 if hasattr(their, "__iter__"):
5447 return self._value == list(their)
5459 return self.__class__(
5463 (self._bound_min, self._bound_max)
5464 if bounds is None else bounds
5466 impl=self.tag if impl is None else impl,
5467 expl=self._expl if expl is None else expl,
5468 default=self.default if default is None else default,
5469 optional=self.optional if optional is None else optional,
5472 def __contains__(self, key):
5473 return key in self._value
5475 def append(self, value):
5476 if not isinstance(value, self.spec.__class__):
5477 raise InvalidValueType((self.spec.__class__,))
5478 if len(self._value) + 1 > self._bound_max:
5481 len(self._value) + 1,
5484 self._value.append(value)
5487 self._assert_ready()
5488 return iter(self._value)
5491 self._assert_ready()
5492 return len(self._value)
5494 def __setitem__(self, key, value):
5495 if not isinstance(value, self.spec.__class__):
5496 raise InvalidValueType((self.spec.__class__,))
5497 self._value[key] = self.spec(value=value)
5499 def __getitem__(self, key):
5500 return self._value[key]
5502 def _encoded_values(self):
5503 return [v.encode() for v in self._value]
5506 v = b"".join(self._encoded_values())
5507 return b"".join((self.tag, len_encode(len(v)), v))
5509 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5511 t, tlen, lv = tag_strip(tlv)
5512 except DecodeError as err:
5513 raise err.__class__(
5515 klass=self.__class__,
5516 decode_path=decode_path,
5521 klass=self.__class__,
5522 decode_path=decode_path,
5528 ctx_bered = ctx.get("bered", False)
5530 l, llen, v = len_decode(lv)
5531 except LenIndefForm as err:
5533 raise err.__class__(
5535 klass=self.__class__,
5536 decode_path=decode_path,
5539 l, llen, v = 0, 1, lv[1:]
5541 except DecodeError as err:
5542 raise err.__class__(
5544 klass=self.__class__,
5545 decode_path=decode_path,
5549 raise NotEnoughData(
5550 "encoded length is longer than data",
5551 klass=self.__class__,
5552 decode_path=decode_path,
5556 v, tail = v[:l], v[l:]
5558 sub_offset = offset + tlen + llen
5560 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5561 value_prev = memoryview(v[:0])
5565 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5567 sub_decode_path = decode_path + (str(len(_value)),)
5568 value, v_tail = spec.decode(
5572 decode_path=sub_decode_path,
5574 _ctx_immutable=False,
5576 value_len = value.fulllen
5578 if value_prev.tobytes() > v[:value_len].tobytes():
5579 if ctx_bered or ctx_allow_unordered_set:
5583 "unordered " + self.asn1_type_name,
5584 klass=self.__class__,
5585 decode_path=sub_decode_path,
5588 value_prev = v[:value_len]
5589 _value.append(value)
5590 sub_offset += value_len
5594 obj = self.__class__(
5597 bounds=(self._bound_min, self._bound_max),
5600 default=self.default,
5601 optional=self.optional,
5602 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5604 except BoundsError as err:
5607 klass=self.__class__,
5608 decode_path=decode_path,
5612 if v[:EOC_LEN].tobytes() != EOC:
5615 klass=self.__class__,
5616 decode_path=decode_path,
5621 obj.ber_encoded = ber_encoded
5626 pp_console_row(next(self.pps())),
5627 ", ".join(repr(v) for v in self._value),
5630 def pps(self, decode_path=()):
5633 asn1_type_name=self.asn1_type_name,
5634 obj_name=self.__class__.__name__,
5635 decode_path=decode_path,
5636 optional=self.optional,
5637 default=self == self.default,
5638 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5639 expl=None if self._expl is None else tag_decode(self._expl),
5644 expl_offset=self.expl_offset if self.expled else None,
5645 expl_tlen=self.expl_tlen if self.expled else None,
5646 expl_llen=self.expl_llen if self.expled else None,
5647 expl_vlen=self.expl_vlen if self.expled else None,
5648 expl_lenindef=self.expl_lenindef,
5649 lenindef=self.lenindef,
5650 ber_encoded=self.ber_encoded,
5653 for i, value in enumerate(self._value):
5654 yield value.pps(decode_path=decode_path + (str(i),))
5655 for pp in self.pps_lenindef(decode_path):
5659 class SetOf(SequenceOf):
5660 """``SET OF`` sequence type
5662 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
5665 tag_default = tag_encode(form=TagFormConstructed, num=17)
5666 asn1_type_name = "SET OF"
5669 raws = self._encoded_values()
5672 return b"".join((self.tag, len_encode(len(v)), v))
5674 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5675 return super(SetOf, self)._decode(
5681 ordering_check=True,
5685 def obj_by_path(pypath): # pragma: no cover
5686 """Import object specified as string Python path
5688 Modules must be separated from classes/functions with ``:``.
5690 >>> obj_by_path("foo.bar:Baz")
5691 <class 'foo.bar.Baz'>
5692 >>> obj_by_path("foo.bar:Baz.boo")
5693 <classmethod 'foo.bar.Baz.boo'>
5695 mod, objs = pypath.rsplit(":", 1)
5696 from importlib import import_module
5697 obj = import_module(mod)
5698 for obj_name in objs.split("."):
5699 obj = getattr(obj, obj_name)
5703 def generic_decoder(): # pragma: no cover
5704 # All of this below is a big hack with self references
5705 choice = PrimitiveTypes()
5706 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
5707 choice.specs["SetOf"] = SetOf(schema=choice)
5708 for i in six_xrange(31):
5709 choice.specs["SequenceOf%d" % i] = SequenceOf(
5713 choice.specs["Any"] = Any()
5715 # Class name equals to type name, to omit it from output
5716 class SEQUENCEOF(SequenceOf):
5724 with_decode_path=False,
5725 decode_path_only=(),
5727 def _pprint_pps(pps):
5729 if hasattr(pp, "_fields"):
5731 decode_path_only != () and
5732 pp.decode_path[:len(decode_path_only)] != decode_path_only
5735 if pp.asn1_type_name == Choice.asn1_type_name:
5737 pp_kwargs = pp._asdict()
5738 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
5739 pp = _pp(**pp_kwargs)
5740 yield pp_console_row(
5745 with_colours=with_colours,
5746 with_decode_path=with_decode_path,
5747 decode_path_len_decrease=len(decode_path_only),
5749 for row in pp_console_blob(
5751 decode_path_len_decrease=len(decode_path_only),
5755 for row in _pprint_pps(pp):
5757 return "\n".join(_pprint_pps(obj.pps()))
5758 return SEQUENCEOF(), pprint_any
5761 def main(): # pragma: no cover
5763 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
5764 parser.add_argument(
5768 help="Skip that number of bytes from the beginning",
5770 parser.add_argument(
5772 help="Python paths to dictionary with OIDs, comma separated",
5774 parser.add_argument(
5776 help="Python path to schema definition to use",
5778 parser.add_argument(
5779 "--defines-by-path",
5780 help="Python path to decoder's defines_by_path",
5782 parser.add_argument(
5784 action="store_true",
5785 help="Disallow BER encoding",
5787 parser.add_argument(
5788 "--print-decode-path",
5789 action="store_true",
5790 help="Print decode paths",
5792 parser.add_argument(
5793 "--decode-path-only",
5794 help="Print only specified decode path",
5796 parser.add_argument(
5798 action="store_true",
5799 help="Allow explicit tag out-of-bound",
5801 parser.add_argument(
5803 type=argparse.FileType("rb"),
5804 help="Path to DER file you want to decode",
5806 args = parser.parse_args()
5807 args.DERFile.seek(args.skip)
5808 der = memoryview(args.DERFile.read())
5809 args.DERFile.close()
5811 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
5812 if args.oids else ()
5815 schema = obj_by_path(args.schema)
5816 from functools import partial
5817 pprinter = partial(pprint, big_blobs=True)
5819 schema, pprinter = generic_decoder()
5821 "bered": not args.nobered,
5822 "allow_expl_oob": args.allow_expl_oob,
5824 if args.defines_by_path is not None:
5825 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
5826 obj, tail = schema().decode(der, ctx=ctx)
5830 with_colours=environ.get("NO_COLOR") is None,
5831 with_decode_path=args.print_decode_path,
5833 () if args.decode_path_only is None else
5834 tuple(args.decode_path_only.split(":"))
5838 print("\nTrailing data: %s" % hexenc(tail))
5841 if __name__ == "__main__":