]> Cypherpunks.ru repositories - pyderasn.git/blob - pyderasn.py
BER Boolean support
[pyderasn.git] / pyderasn.py
1 #!/usr/bin/env python
2 # coding: utf-8
3 # PyDERASN -- Python ASN.1 DER codec with abstract structures
4 # Copyright (C) 2017-2018 Sergey Matveev <stargrave@stargrave.org>
5 #
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, either version 3 of the
9 # License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU Lesser General Public License for more details.
15 #
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this program.  If not, see
18 # <http://www.gnu.org/licenses/>.
19 """Python ASN.1 DER codec with abstract structures
20
21 This library allows you to marshal and unmarshal various structures in
22 ASN.1 DER format, like this:
23
24     >>> i = Integer(123)
25     >>> raw = i.encode()
26     >>> Integer().decode(raw) == i
27     True
28
29 There are primitive types, holding single values
30 (:py:class:`pyderasn.BitString`,
31 :py:class:`pyderasn.Boolean`,
32 :py:class:`pyderasn.Enumerated`,
33 :py:class:`pyderasn.GeneralizedTime`,
34 :py:class:`pyderasn.Integer`,
35 :py:class:`pyderasn.Null`,
36 :py:class:`pyderasn.ObjectIdentifier`,
37 :py:class:`pyderasn.OctetString`,
38 :py:class:`pyderasn.UTCTime`,
39 :py:class:`various strings <pyderasn.CommonString>`
40 (:py:class:`pyderasn.BMPString`,
41 :py:class:`pyderasn.GeneralString`,
42 :py:class:`pyderasn.GraphicString`,
43 :py:class:`pyderasn.IA5String`,
44 :py:class:`pyderasn.ISO646String`,
45 :py:class:`pyderasn.NumericString`,
46 :py:class:`pyderasn.PrintableString`,
47 :py:class:`pyderasn.T61String`,
48 :py:class:`pyderasn.TeletexString`,
49 :py:class:`pyderasn.UniversalString`,
50 :py:class:`pyderasn.UTF8String`,
51 :py:class:`pyderasn.VideotexString`,
52 :py:class:`pyderasn.VisibleString`)),
53 constructed types, holding multiple primitive types
54 (:py:class:`pyderasn.Sequence`,
55 :py:class:`pyderasn.SequenceOf`,
56 :py:class:`pyderasn.Set`,
57 :py:class:`pyderasn.SetOf`),
58 and special types like
59 :py:class:`pyderasn.Any` and
60 :py:class:`pyderasn.Choice`.
61
62 Common for most types
63 ---------------------
64
65 Tags
66 ____
67
68 Most types in ASN.1 has specific tag for them. ``Obj.tag_default`` is
69 the default tag used during coding process. You can override it with
70 either ``IMPLICIT`` (using ``impl`` keyword argument), or
71 ``EXPLICIT`` one (using ``expl`` keyword argument). Both arguments take
72 raw binary string, containing that tag. You can **not** set implicit and
73 explicit tags simultaneously.
74
75 There are :py:func:`pyderasn.tag_ctxp` and :py:func:`pyderasn.tag_ctxc`
76 functions, allowing you to easily create ``CONTEXT``
77 ``PRIMITIVE``/``CONSTRUCTED`` tags, by specifying only the required tag
78 number. Pay attention that explicit tags always have *constructed* tag
79 (``tag_ctxc``), but implicit tags for primitive types are primitive
80 (``tag_ctxp``).
81
82 ::
83
84     >>> Integer(impl=tag_ctxp(1))
85     [1] INTEGER
86     >>> Integer(expl=tag_ctxc(2))
87     [2] EXPLICIT INTEGER
88
89 Implicit tag is not explicitly shown.
90
91 Two objects of the same type, but with different implicit/explicit tags
92 are **not** equal.
93
94 You can get object's effective tag (either default or implicited) through
95 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
96 function::
97
98     >>> tag_decode(tag_ctxc(123))
99     (128, 32, 123)
100     >>> klass, form, num = tag_decode(tag_ctxc(123))
101     >>> klass == TagClassContext
102     True
103     >>> form == TagFormConstructed
104     True
105
106 To determine if object has explicit tag, use ``expled`` boolean property
107 and ``expl_tag`` property, returning explicit tag's value.
108
109 Default/optional
110 ________________
111
112 Many objects in sequences could be ``OPTIONAL`` and could have
113 ``DEFAULT`` value. You can specify that object's property using
114 corresponding keyword arguments.
115
116     >>> Integer(optional=True, default=123)
117     INTEGER 123 OPTIONAL DEFAULT
118
119 Those specifications do not play any role in primitive value encoding,
120 but are taken into account when dealing with sequences holding them. For
121 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
122 ``version`` field::
123
124     class Version(Integer):
125         schema = (
126             ("v1", 0),
127             ("v2", 1),
128             ("v3", 2),
129         )
130     class TBSCertificate(Sequence):
131         schema = (
132             ("version", Version(expl=tag_ctxc(0), default="v1")),
133         [...]
134
135 When default argument is used and value is not specified, then it equals
136 to default one.
137
138 .. _bounds:
139
140 Size constraints
141 ________________
142
143 Some objects give ability to set value size constraints. This is either
144 possible integer value, or allowed length of various strings and
145 sequences. Constraints are set in the following way::
146
147     class X(...):
148         bounds = (MIN, MAX)
149
150 And values satisfaction is checked as: ``MIN <= X <= MAX``.
151
152 For simplicity you can also set bounds the following way::
153
154     bounded_x = X(bounds=(MIN, MAX))
155
156 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
157 raised.
158
159 Common methods
160 ______________
161
162 All objects have ``ready`` boolean property, that tells if object is
163 ready to be encoded. If that kind of action is performed on unready
164 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
165
166 All objects have ``copy()`` method, that returns their copy, that can be
167 safely mutated.
168
169 .. _decoding:
170
171 Decoding
172 --------
173
174 Decoding is performed using ``decode()`` method. ``offset`` optional
175 argument could be used to set initial object's offset in the binary
176 data, for convenience. It returns decoded object and remaining
177 unmarshalled data (tail). Internally all work is done on
178 ``memoryview(data)``, and you can leave returning tail as a memoryview,
179 by specifying ``leavemm=True`` argument.
180
181 When object is decoded, ``decoded`` property is true and you can safely
182 use following properties:
183
184 * ``offset`` -- position including initial offset where object's tag starts
185 * ``tlen`` -- length of object's tag
186 * ``llen`` -- length of object's length value
187 * ``vlen`` -- length of object's value
188 * ``tlvlen`` -- length of the whole object
189
190 Pay attention that those values do **not** include anything related to
191 explicit tag. If you want to know information about it, then use:
192 ``expled`` (to know if explicit tag is set), ``expl_offset`` (it is
193 lesser than ``offset``), ``expl_tlen``, ``expl_llen``, ``expl_vlen``
194 (that actually equals to ordinary ``tlvlen``).
195
196 When error occurs, then :py:exc:`pyderasn.DecodeError` is raised.
197
198 .. _ctx:
199
200 Context
201 _______
202
203 You can specify so called context keyword argument during ``decode()``
204 invocation. It is dictionary containing various options governing
205 decoding process.
206
207 Currently available context options:
208
209 * :ref:`defines_by_path <defines_by_path_ctx>`
210 * :ref:`strict_default_existence <strict_default_existence_ctx>`
211
212 .. _pprinting:
213
214 Pretty printing
215 ---------------
216
217 All objects have ``pps()`` method, that is a generator of
218 :py:class:`pyderasn.PP` namedtuple, holding various raw information
219 about the object. If ``pps`` is called on sequences, then all underlying
220 ``PP`` will be yielded.
221
222 You can use :py:func:`pyderasn.pp_console_row` function, converting
223 those ``PP`` to human readable string. Actually exactly it is used for
224 all object ``repr``. But it is easy to write custom formatters.
225
226     >>> from pyderasn import pprint
227     >>> encoded = Integer(-12345).encode()
228     >>> obj, tail = Integer().decode(encoded)
229     >>> print(pprint(obj))
230         0   [1,1,   2] INTEGER -12345
231
232 .. _definedby:
233
234 DEFINED BY
235 ----------
236
237 ASN.1 structures often have ANY and OCTET STRING fields, that are
238 DEFINED BY some previously met ObjectIdentifier. This library provides
239 ability to specify mapping between some OID and field that must be
240 decoded with specific specification.
241
242 defines kwarg
243 _____________
244
245 :py:class:`pyderasn.ObjectIdentifier` field inside
246 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
247 necessary for decoding structures. For example, CMS (:rfc:`5652`)
248 container::
249
250     class ContentInfo(Sequence):
251         schema = (
252             ("contentType", ContentType(defines=((("content",), {
253                 id_digestedData: DigestedData(),
254                 id_signedData: SignedData(),
255             }),))),
256             ("content", Any(expl=tag_ctxc(0))),
257         )
258
259 ``contentType`` field tells that it defines that ``content`` must be
260 decoded with ``SignedData`` specification, if ``contentType`` equals to
261 ``id-signedData``. The same applies to ``DigestedData``. If
262 ``contentType`` contains unknown OID, then no automatic decoding is
263 done.
264
265 You can specify multiple fields, that will be autodecoded -- that is why
266 ``defines`` kwarg is a sequence. You can specify defined field
267 relatively or absolutely to current decode path. For example ``defines``
268 for AlgorithmIdentifier of X.509's
269 ``tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm``::
270
271         (
272             (("parameters",), {
273                 id_ecPublicKey: ECParameters(),
274                 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
275             }),
276             (("..", "subjectPublicKey"), {
277                 id_rsaEncryption: RSAPublicKey(),
278                 id_GostR3410_2001: OctetString(),
279             }),
280         ),
281
282 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
283 autodecode its parameters inside SPKI's algorithm and its public key
284 itself.
285
286 Following types can be automatically decoded (DEFINED BY):
287
288 * :py:class:`pyderasn.Any`
289 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
290 * :py:class:`pyderasn.OctetString`
291 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
292   ``Any``/``BitString``/``OctetString``-s
293
294 When any of those fields is automatically decoded, then ``.defined``
295 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
296 was defined, ``value`` contains corresponding decoded value. For example
297 above, ``content_info["content"].defined == (id_signedData,
298 signed_data)``.
299
300 .. _defines_by_path_ctx:
301
302 defines_by_path context option
303 ______________________________
304
305 Sometimes you either can not or do not want to explicitly set *defines*
306 in the scheme. You can dynamically apply those definitions when calling
307 ``.decode()`` method.
308
309 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
310 value must be sequence of following tuples::
311
312     (decode_path, defines)
313
314 where ``decode_path`` is a tuple holding so-called decode path to the
315 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
316 ``defines``, holding exactly the same value as accepted in its keyword
317 argument.
318
319 For example, again for CMS, you want to automatically decode
320 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
321 structures it may hold. Also, automatically decode ``controlSequence``
322 of ``PKIResponse``::
323
324     content_info, tail = ContentInfo().decode(data, defines_by_path=(
325         (
326             ("contentType",),
327             ((("content",), {id_signedData: SignedData()}),),
328         ),
329         (
330             (
331                 "content",
332                 DecodePathDefBy(id_signedData),
333                 "encapContentInfo",
334                 "eContentType",
335             ),
336             ((("eContent",), {
337                 id_cct_PKIData: PKIData(),
338                 id_cct_PKIResponse: PKIResponse(),
339             })),
340         ),
341         (
342             (
343                 "content",
344                 DecodePathDefBy(id_signedData),
345                 "encapContentInfo",
346                 "eContent",
347                 DecodePathDefBy(id_cct_PKIResponse),
348                 "controlSequence",
349                 any,
350                 "attrType",
351             ),
352             ((("attrValues",), {
353                 id_cmc_recipientNonce: RecipientNonce(),
354                 id_cmc_senderNonce: SenderNonce(),
355                 id_cmc_statusInfoV2: CMCStatusInfoV2(),
356                 id_cmc_transactionId: TransactionId(),
357             })),
358         ),
359     ))
360
361 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
362 First function is useful for path construction when some automatic
363 decoding is already done. ``any`` means literally any value it meet --
364 useful for SEQUENCE/SET OF-s.
365
366 Primitive types
367 ---------------
368
369 Boolean
370 _______
371 .. autoclass:: pyderasn.Boolean
372    :members: __init__
373
374 Integer
375 _______
376 .. autoclass:: pyderasn.Integer
377    :members: __init__
378
379 BitString
380 _________
381 .. autoclass:: pyderasn.BitString
382    :members: __init__
383
384 OctetString
385 ___________
386 .. autoclass:: pyderasn.OctetString
387    :members: __init__
388
389 Null
390 ____
391 .. autoclass:: pyderasn.Null
392    :members: __init__
393
394 ObjectIdentifier
395 ________________
396 .. autoclass:: pyderasn.ObjectIdentifier
397    :members: __init__
398
399 Enumerated
400 __________
401 .. autoclass:: pyderasn.Enumerated
402
403 CommonString
404 ____________
405 .. autoclass:: pyderasn.CommonString
406
407 UTCTime
408 _______
409 .. autoclass:: pyderasn.UTCTime
410    :members: __init__, todatetime
411
412 GeneralizedTime
413 _______________
414 .. autoclass:: pyderasn.GeneralizedTime
415
416 Special types
417 -------------
418
419 Choice
420 ______
421 .. autoclass:: pyderasn.Choice
422    :members: __init__
423
424 PrimitiveTypes
425 ______________
426 .. autoclass:: PrimitiveTypes
427
428 Any
429 ___
430 .. autoclass:: pyderasn.Any
431    :members: __init__
432
433 Constructed types
434 -----------------
435
436 Sequence
437 ________
438 .. autoclass:: pyderasn.Sequence
439    :members: __init__
440
441 Set
442 ___
443 .. autoclass:: pyderasn.Set
444    :members: __init__
445
446 SequenceOf
447 __________
448 .. autoclass:: pyderasn.SequenceOf
449    :members: __init__
450
451 SetOf
452 _____
453 .. autoclass:: pyderasn.SetOf
454    :members: __init__
455
456 Various
457 -------
458
459 .. autofunction:: pyderasn.abs_decode_path
460 .. autofunction:: pyderasn.hexenc
461 .. autofunction:: pyderasn.hexdec
462 .. autofunction:: pyderasn.tag_encode
463 .. autofunction:: pyderasn.tag_decode
464 .. autofunction:: pyderasn.tag_ctxp
465 .. autofunction:: pyderasn.tag_ctxc
466 .. autoclass:: pyderasn.Obj
467 """
468
469 from codecs import getdecoder
470 from codecs import getencoder
471 from collections import namedtuple
472 from collections import OrderedDict
473 from datetime import datetime
474 from math import ceil
475 from os import environ
476 from string import digits
477
478 from six import add_metaclass
479 from six import binary_type
480 from six import byte2int
481 from six import indexbytes
482 from six import int2byte
483 from six import integer_types
484 from six import iterbytes
485 from six import PY2
486 from six import string_types
487 from six import text_type
488 from six.moves import xrange as six_xrange
489
490
491 try:
492     from termcolor import colored
493 except ImportError:
494     def colored(what, *args):
495         return what
496
497
498 __all__ = (
499     "Any",
500     "BitString",
501     "BMPString",
502     "Boolean",
503     "BoundsError",
504     "Choice",
505     "DecodeError",
506     "DecodePathDefBy",
507     "Enumerated",
508     "GeneralizedTime",
509     "GeneralString",
510     "GraphicString",
511     "hexdec",
512     "hexenc",
513     "IA5String",
514     "Integer",
515     "InvalidLength",
516     "InvalidOID",
517     "InvalidValueType",
518     "ISO646String",
519     "NotEnoughData",
520     "Null",
521     "NumericString",
522     "obj_by_path",
523     "ObjectIdentifier",
524     "ObjNotReady",
525     "ObjUnknown",
526     "OctetString",
527     "PrimitiveTypes",
528     "PrintableString",
529     "Sequence",
530     "SequenceOf",
531     "Set",
532     "SetOf",
533     "T61String",
534     "tag_ctxc",
535     "tag_ctxp",
536     "tag_decode",
537     "TagClassApplication",
538     "TagClassContext",
539     "TagClassPrivate",
540     "TagClassUniversal",
541     "TagFormConstructed",
542     "TagFormPrimitive",
543     "TagMismatch",
544     "TeletexString",
545     "UniversalString",
546     "UTCTime",
547     "UTF8String",
548     "VideotexString",
549     "VisibleString",
550 )
551
552 TagClassUniversal = 0
553 TagClassApplication = 1 << 6
554 TagClassContext = 1 << 7
555 TagClassPrivate = 1 << 6 | 1 << 7
556 TagFormPrimitive = 0
557 TagFormConstructed = 1 << 5
558 TagClassReprs = {
559     TagClassContext: "",
560     TagClassApplication: "APPLICATION ",
561     TagClassPrivate: "PRIVATE ",
562     TagClassUniversal: "UNIV ",
563 }
564
565
566 ########################################################################
567 # Errors
568 ########################################################################
569
570 class DecodeError(Exception):
571     def __init__(self, msg="", klass=None, decode_path=(), offset=0):
572         """
573         :param str msg: reason of decode failing
574         :param klass: optional exact DecodeError inherited class (like
575                       :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
576                       :py:exc:`InvalidLength`)
577         :param decode_path: tuple of strings. It contains human
578                             readable names of the fields through which
579                             decoding process has passed
580         :param int offset: binary offset where failure happened
581         """
582         super(DecodeError, self).__init__()
583         self.msg = msg
584         self.klass = klass
585         self.decode_path = decode_path
586         self.offset = offset
587
588     def __str__(self):
589         return " ".join(
590             c for c in (
591                 "" if self.klass is None else self.klass.__name__,
592                 (
593                     ("(%s)" % ".".join(str(dp) for dp in self.decode_path))
594                     if len(self.decode_path) > 0 else ""
595                 ),
596                 ("(at %d)" % self.offset) if self.offset > 0 else "",
597                 self.msg,
598             ) if c != ""
599         )
600
601     def __repr__(self):
602         return "%s(%s)" % (self.__class__.__name__, self)
603
604
605 class NotEnoughData(DecodeError):
606     pass
607
608
609 class TagMismatch(DecodeError):
610     pass
611
612
613 class InvalidLength(DecodeError):
614     pass
615
616
617 class InvalidOID(DecodeError):
618     pass
619
620
621 class ObjUnknown(ValueError):
622     def __init__(self, name):
623         super(ObjUnknown, self).__init__()
624         self.name = name
625
626     def __str__(self):
627         return "object is unknown: %s" % self.name
628
629     def __repr__(self):
630         return "%s(%s)" % (self.__class__.__name__, self)
631
632
633 class ObjNotReady(ValueError):
634     def __init__(self, name):
635         super(ObjNotReady, self).__init__()
636         self.name = name
637
638     def __str__(self):
639         return "object is not ready: %s" % self.name
640
641     def __repr__(self):
642         return "%s(%s)" % (self.__class__.__name__, self)
643
644
645 class InvalidValueType(ValueError):
646     def __init__(self, expected_types):
647         super(InvalidValueType, self).__init__()
648         self.expected_types = expected_types
649
650     def __str__(self):
651         return "invalid value type, expected: %s" % ", ".join(
652             [repr(t) for t in self.expected_types]
653         )
654
655     def __repr__(self):
656         return "%s(%s)" % (self.__class__.__name__, self)
657
658
659 class BoundsError(ValueError):
660     def __init__(self, bound_min, value, bound_max):
661         super(BoundsError, self).__init__()
662         self.bound_min = bound_min
663         self.value = value
664         self.bound_max = bound_max
665
666     def __str__(self):
667         return "unsatisfied bounds: %s <= %s <= %s" % (
668             self.bound_min,
669             self.value,
670             self.bound_max,
671         )
672
673     def __repr__(self):
674         return "%s(%s)" % (self.__class__.__name__, self)
675
676
677 ########################################################################
678 # Basic coders
679 ########################################################################
680
681 _hexdecoder = getdecoder("hex")
682 _hexencoder = getencoder("hex")
683
684
685 def hexdec(data):
686     """Binary data to hexadecimal string convert
687     """
688     return _hexdecoder(data)[0]
689
690
691 def hexenc(data):
692     """Hexadecimal string to binary data convert
693     """
694     return _hexencoder(data)[0].decode("ascii")
695
696
697 def int_bytes_len(num, byte_len=8):
698     if num == 0:
699         return 1
700     return int(ceil(float(num.bit_length()) / byte_len))
701
702
703 def zero_ended_encode(num):
704     octets = bytearray(int_bytes_len(num, 7))
705     i = len(octets) - 1
706     octets[i] = num & 0x7F
707     num >>= 7
708     i -= 1
709     while num > 0:
710         octets[i] = 0x80 | (num & 0x7F)
711         num >>= 7
712         i -= 1
713     return bytes(octets)
714
715
716 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
717     """Encode tag to binary form
718
719     :param int num: tag's number
720     :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
721                       :py:data:`pyderasn.TagClassContext`,
722                       :py:data:`pyderasn.TagClassApplication`,
723                       :py:data:`pyderasn.TagClassPrivate`)
724     :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
725                      :py:data:`pyderasn.TagFormConstructed`)
726     """
727     if num < 31:
728         # [XX|X|.....]
729         return int2byte(klass | form | num)
730     # [XX|X|11111][1.......][1.......] ... [0.......]
731     return int2byte(klass | form | 31) + zero_ended_encode(num)
732
733
734 def tag_decode(tag):
735     """Decode tag from binary form
736
737     .. warning::
738
739        No validation is performed, assuming that it has already passed.
740
741     It returns tuple with three integers, as
742     :py:func:`pyderasn.tag_encode` accepts.
743     """
744     first_octet = byte2int(tag)
745     klass = first_octet & 0xC0
746     form = first_octet & 0x20
747     if first_octet & 0x1F < 0x1F:
748         return (klass, form, first_octet & 0x1F)
749     num = 0
750     for octet in iterbytes(tag[1:]):
751         num <<= 7
752         num |= octet & 0x7F
753     return (klass, form, num)
754
755
756 def tag_ctxp(num):
757     """Create CONTEXT PRIMITIVE tag
758     """
759     return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
760
761
762 def tag_ctxc(num):
763     """Create CONTEXT CONSTRUCTED tag
764     """
765     return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
766
767
768 def tag_strip(data):
769     """Take off tag from the data
770
771     :returns: (encoded tag, tag length, remaining data)
772     """
773     if len(data) == 0:
774         raise NotEnoughData("no data at all")
775     if byte2int(data) & 0x1F < 31:
776         return data[:1], 1, data[1:]
777     i = 0
778     while True:
779         i += 1
780         if i == len(data):
781             raise DecodeError("unfinished tag")
782         if indexbytes(data, i) & 0x80 == 0:
783             break
784     i += 1
785     return data[:i], i, data[i:]
786
787
788 def len_encode(l):
789     if l < 0x80:
790         return int2byte(l)
791     octets = bytearray(int_bytes_len(l) + 1)
792     octets[0] = 0x80 | (len(octets) - 1)
793     for i in six_xrange(len(octets) - 1, 0, -1):
794         octets[i] = l & 0xFF
795         l >>= 8
796     return bytes(octets)
797
798
799 def len_decode(data):
800     if len(data) == 0:
801         raise NotEnoughData("no data at all")
802     first_octet = byte2int(data)
803     if first_octet & 0x80 == 0:
804         return first_octet, 1, data[1:]
805     octets_num = first_octet & 0x7F
806     if octets_num + 1 > len(data):
807         raise NotEnoughData("encoded length is longer than data")
808     if octets_num == 0:
809         raise DecodeError("long form instead of short one")
810     if byte2int(data[1:]) == 0:
811         raise DecodeError("leading zeros")
812     l = 0
813     for v in iterbytes(data[1:1 + octets_num]):
814         l = (l << 8) | v
815     if l <= 127:
816         raise DecodeError("long form instead of short one")
817     return l, 1 + octets_num, data[1 + octets_num:]
818
819
820 ########################################################################
821 # Base class
822 ########################################################################
823
824 class AutoAddSlots(type):
825     def __new__(mcs, name, bases, _dict):
826         _dict["__slots__"] = _dict.get("__slots__", ())
827         return type.__new__(mcs, name, bases, _dict)
828
829
830 @add_metaclass(AutoAddSlots)
831 class Obj(object):
832     """Common ASN.1 object class
833
834     All ASN.1 types are inherited from it. It has metaclass that
835     automatically adds ``__slots__`` to all inherited classes.
836     """
837     __slots__ = (
838         "tag",
839         "_value",
840         "_expl",
841         "default",
842         "optional",
843         "offset",
844         "llen",
845         "vlen",
846         "bered",
847     )
848
849     def __init__(
850             self,
851             impl=None,
852             expl=None,
853             default=None,
854             optional=False,
855             _decoded=(0, 0, 0),
856     ):
857         self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
858         self._expl = getattr(self, "expl", None) if expl is None else expl
859         if self.tag != self.tag_default and self._expl is not None:
860             raise ValueError(
861                 "implicit and explicit tags can not be set simultaneously"
862             )
863         if default is not None:
864             optional = True
865         self.optional = optional
866         self.offset, self.llen, self.vlen = _decoded
867         self.default = None
868         self.bered = False
869
870     @property
871     def ready(self):  # pragma: no cover
872         """Is object ready to be encoded?
873         """
874         raise NotImplementedError()
875
876     def _assert_ready(self):
877         if not self.ready:
878             raise ObjNotReady(self.__class__.__name__)
879
880     @property
881     def decoded(self):
882         """Is object decoded?
883         """
884         return (self.llen + self.vlen) > 0
885
886     def copy(self):  # pragma: no cover
887         """Make a copy of object, safe to be mutated
888         """
889         raise NotImplementedError()
890
891     @property
892     def tlen(self):
893         return len(self.tag)
894
895     @property
896     def tlvlen(self):
897         return self.tlen + self.llen + self.vlen
898
899     def __str__(self):  # pragma: no cover
900         return self.__bytes__() if PY2 else self.__unicode__()
901
902     def __ne__(self, their):
903         return not(self == their)
904
905     def __gt__(self, their):  # pragma: no cover
906         return not(self < their)
907
908     def __le__(self, their):  # pragma: no cover
909         return (self == their) or (self < their)
910
911     def __ge__(self, their):  # pragma: no cover
912         return (self == their) or (self > their)
913
914     def _encode(self):  # pragma: no cover
915         raise NotImplementedError()
916
917     def _decode(self, tlv, offset, decode_path, ctx, tag_only):  # pragma: no cover
918         raise NotImplementedError()
919
920     def encode(self):
921         raw = self._encode()
922         if self._expl is None:
923             return raw
924         return b"".join((self._expl, len_encode(len(raw)), raw))
925
926     def decode(
927             self,
928             data,
929             offset=0,
930             leavemm=False,
931             decode_path=(),
932             ctx=None,
933             tag_only=False,
934     ):
935         """Decode the data
936
937         :param data: either binary or memoryview
938         :param int offset: initial data's offset
939         :param bool leavemm: do we need to leave memoryview of remaining
940                     data as is, or convert it to bytes otherwise
941         :param ctx: optional :ref:`context <ctx>` governing decoding process.
942         :param tag_only: decode only the tag, without length and contents
943                          (used only in Choice and Set structures, trying to
944                          determine if tag satisfies the scheme)
945         :returns: (Obj, remaining data)
946         """
947         if ctx is None:
948             ctx = {}
949         tlv = memoryview(data)
950         if self._expl is None:
951             result = self._decode(
952                 tlv,
953                 offset,
954                 decode_path=decode_path,
955                 ctx=ctx,
956                 tag_only=tag_only,
957             )
958             if tag_only:
959                 return
960             obj, tail = result
961         else:
962             try:
963                 t, tlen, lv = tag_strip(tlv)
964             except DecodeError as err:
965                 raise err.__class__(
966                     msg=err.msg,
967                     klass=self.__class__,
968                     decode_path=decode_path,
969                     offset=offset,
970                 )
971             if t != self._expl:
972                 raise TagMismatch(
973                     klass=self.__class__,
974                     decode_path=decode_path,
975                     offset=offset,
976                 )
977             try:
978                 l, llen, v = len_decode(lv)
979             except DecodeError as err:
980                 raise err.__class__(
981                     msg=err.msg,
982                     klass=self.__class__,
983                     decode_path=decode_path,
984                     offset=offset,
985                 )
986             if l > len(v):
987                 raise NotEnoughData(
988                     "encoded length is longer than data",
989                     klass=self.__class__,
990                     decode_path=decode_path,
991                     offset=offset,
992                 )
993             result = self._decode(
994                 v,
995                 offset=offset + tlen + llen,
996                 decode_path=decode_path,
997                 ctx=ctx,
998                 tag_only=tag_only,
999             )
1000             if tag_only:
1001                 return
1002             obj, tail = result
1003         return obj, (tail if leavemm else tail.tobytes())
1004
1005     @property
1006     def expled(self):
1007         return self._expl is not None
1008
1009     @property
1010     def expl_tag(self):
1011         return self._expl
1012
1013     @property
1014     def expl_tlen(self):
1015         return len(self._expl)
1016
1017     @property
1018     def expl_llen(self):
1019         return len(len_encode(self.tlvlen))
1020
1021     @property
1022     def expl_offset(self):
1023         return self.offset - self.expl_tlen - self.expl_llen
1024
1025     @property
1026     def expl_vlen(self):
1027         return self.tlvlen
1028
1029     @property
1030     def expl_tlvlen(self):
1031         return self.expl_tlen + self.expl_llen + self.expl_vlen
1032
1033
1034 class DecodePathDefBy(object):
1035     """DEFINED BY representation inside decode path
1036     """
1037     __slots__ = ("defined_by",)
1038
1039     def __init__(self, defined_by):
1040         self.defined_by = defined_by
1041
1042     def __ne__(self, their):
1043         return not(self == their)
1044
1045     def __eq__(self, their):
1046         if not isinstance(their, self.__class__):
1047             return False
1048         return self.defined_by == their.defined_by
1049
1050     def __str__(self):
1051         return "DEFINED BY " + str(self.defined_by)
1052
1053     def __repr__(self):
1054         return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1055
1056
1057 ########################################################################
1058 # Pretty printing
1059 ########################################################################
1060
1061 PP = namedtuple("PP", (
1062     "asn1_type_name",
1063     "obj_name",
1064     "decode_path",
1065     "value",
1066     "blob",
1067     "optional",
1068     "default",
1069     "impl",
1070     "expl",
1071     "offset",
1072     "tlen",
1073     "llen",
1074     "vlen",
1075     "expl_offset",
1076     "expl_tlen",
1077     "expl_llen",
1078     "expl_vlen",
1079 ))
1080
1081
1082 def _pp(
1083         asn1_type_name="unknown",
1084         obj_name="unknown",
1085         decode_path=(),
1086         value=None,
1087         blob=None,
1088         optional=False,
1089         default=False,
1090         impl=None,
1091         expl=None,
1092         offset=0,
1093         tlen=0,
1094         llen=0,
1095         vlen=0,
1096         expl_offset=None,
1097         expl_tlen=None,
1098         expl_llen=None,
1099         expl_vlen=None,
1100 ):
1101     return PP(
1102         asn1_type_name,
1103         obj_name,
1104         decode_path,
1105         value,
1106         blob,
1107         optional,
1108         default,
1109         impl,
1110         expl,
1111         offset,
1112         tlen,
1113         llen,
1114         vlen,
1115         expl_offset,
1116         expl_tlen,
1117         expl_llen,
1118         expl_vlen,
1119     )
1120
1121
1122 def _colorize(what, colour, with_colours, attrs=("bold",)):
1123     return colored(what, colour, attrs=attrs) if with_colours else what
1124
1125
1126 def pp_console_row(
1127         pp,
1128         oids=None,
1129         with_offsets=False,
1130         with_blob=True,
1131         with_colours=False,
1132 ):
1133     cols = []
1134     if with_offsets:
1135         col = "%5d%s" % (
1136             pp.offset,
1137             (
1138                 "  " if pp.expl_offset is None else
1139                 ("-%d" % (pp.offset - pp.expl_offset))
1140             ),
1141         )
1142         cols.append(_colorize(col, "red", with_colours, ()))
1143         col = "[%d,%d,%4d]" % (pp.tlen, pp.llen, pp.vlen)
1144         cols.append(_colorize(col, "green", with_colours, ()))
1145     if len(pp.decode_path) > 0:
1146         cols.append(" ." * (len(pp.decode_path)))
1147         ent = pp.decode_path[-1]
1148         if isinstance(ent, DecodePathDefBy):
1149             cols.append(_colorize("DEFINED BY", "red", with_colours, ("reverse",)))
1150             value = str(ent.defined_by)
1151             if (
1152                     oids is not None and
1153                     ent.defined_by.asn1_type_name ==
1154                     ObjectIdentifier.asn1_type_name and
1155                     value in oids
1156             ):
1157                 cols.append(_colorize("%s:" % oids[value], "green", with_colours))
1158             else:
1159                 cols.append(_colorize("%s:" % value, "white", with_colours, ("reverse",)))
1160         else:
1161             cols.append(_colorize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1162     if pp.expl is not None:
1163         klass, _, num = pp.expl
1164         col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1165         cols.append(_colorize(col, "blue", with_colours))
1166     if pp.impl is not None:
1167         klass, _, num = pp.impl
1168         col = "[%s%d]" % (TagClassReprs[klass], num)
1169         cols.append(_colorize(col, "blue", with_colours))
1170     if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1171         cols.append(_colorize(pp.obj_name, "magenta", with_colours))
1172     cols.append(_colorize(pp.asn1_type_name, "cyan", with_colours))
1173     if pp.value is not None:
1174         value = pp.value
1175         cols.append(_colorize(value, "white", with_colours, ("reverse",)))
1176         if (
1177                 oids is not None and
1178                 pp.asn1_type_name == ObjectIdentifier.asn1_type_name and
1179                 value in oids
1180         ):
1181             cols.append(_colorize("(%s)" % oids[value], "green", with_colours))
1182     if with_blob:
1183         if isinstance(pp.blob, binary_type):
1184             cols.append(hexenc(pp.blob))
1185         elif isinstance(pp.blob, tuple):
1186             cols.append(", ".join(pp.blob))
1187     if pp.optional:
1188         cols.append(_colorize("OPTIONAL", "red", with_colours))
1189     if pp.default:
1190         cols.append(_colorize("DEFAULT", "red", with_colours))
1191     return " ".join(cols)
1192
1193
1194 def pp_console_blob(pp):
1195     cols = [" " * len("XXXXXYY [X,X,XXXX]")]
1196     if len(pp.decode_path) > 0:
1197         cols.append(" ." * (len(pp.decode_path) + 1))
1198     if isinstance(pp.blob, binary_type):
1199         blob = hexenc(pp.blob).upper()
1200         for i in range(0, len(blob), 32):
1201             chunk = blob[i:i + 32]
1202             yield " ".join(cols + [":".join(
1203                 chunk[j:j + 2] for j in range(0, len(chunk), 2)
1204             )])
1205     elif isinstance(pp.blob, tuple):
1206         yield " ".join(cols + [", ".join(pp.blob)])
1207
1208
1209 def pprint(obj, oids=None, big_blobs=False, with_colours=False):
1210     """Pretty print object
1211
1212     :param Obj obj: object you want to pretty print
1213     :param oids: ``OID <-> humand readable string`` dictionary. When OID
1214                  from it is met, then its humand readable form is printed
1215     :param big_blobs: if large binary objects are met (like OctetString
1216                       values), do we need to print them too, on separate
1217                       lines
1218     :param with_colours: colourize output, if ``termcolor`` library
1219                          is available
1220     """
1221     def _pprint_pps(pps):
1222         for pp in pps:
1223             if hasattr(pp, "_fields"):
1224                 if big_blobs:
1225                     yield pp_console_row(
1226                         pp,
1227                         oids=oids,
1228                         with_offsets=True,
1229                         with_blob=False,
1230                         with_colours=with_colours,
1231                     )
1232                     for row in pp_console_blob(pp):
1233                         yield row
1234                 else:
1235                     yield pp_console_row(
1236                         pp,
1237                         oids=oids,
1238                         with_offsets=True,
1239                         with_blob=True,
1240                         with_colours=with_colours,
1241                     )
1242             else:
1243                 for row in _pprint_pps(pp):
1244                     yield row
1245     return "\n".join(_pprint_pps(obj.pps()))
1246
1247
1248 ########################################################################
1249 # ASN.1 primitive types
1250 ########################################################################
1251
1252 class Boolean(Obj):
1253     """``BOOLEAN`` boolean type
1254
1255     >>> b = Boolean(True)
1256     BOOLEAN True
1257     >>> b == Boolean(True)
1258     True
1259     >>> bool(b)
1260     True
1261     """
1262     __slots__ = ()
1263     tag_default = tag_encode(1)
1264     asn1_type_name = "BOOLEAN"
1265
1266     def __init__(
1267             self,
1268             value=None,
1269             impl=None,
1270             expl=None,
1271             default=None,
1272             optional=False,
1273             _decoded=(0, 0, 0),
1274     ):
1275         """
1276         :param value: set the value. Either boolean type, or
1277                       :py:class:`pyderasn.Boolean` object
1278         :param bytes impl: override default tag with ``IMPLICIT`` one
1279         :param bytes expl: override default tag with ``EXPLICIT`` one
1280         :param default: set default value. Type same as in ``value``
1281         :param bool optional: is object ``OPTIONAL`` in sequence
1282         """
1283         super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1284         self._value = None if value is None else self._value_sanitize(value)
1285         if default is not None:
1286             default = self._value_sanitize(default)
1287             self.default = self.__class__(
1288                 value=default,
1289                 impl=self.tag,
1290                 expl=self._expl,
1291             )
1292             if value is None:
1293                 self._value = default
1294
1295     def _value_sanitize(self, value):
1296         if issubclass(value.__class__, Boolean):
1297             return value._value
1298         if isinstance(value, bool):
1299             return value
1300         raise InvalidValueType((self.__class__, bool))
1301
1302     @property
1303     def ready(self):
1304         return self._value is not None
1305
1306     def copy(self):
1307         obj = self.__class__()
1308         obj._value = self._value
1309         obj.tag = self.tag
1310         obj._expl = self._expl
1311         obj.default = self.default
1312         obj.optional = self.optional
1313         obj.offset = self.offset
1314         obj.llen = self.llen
1315         obj.vlen = self.vlen
1316         return obj
1317
1318     def __nonzero__(self):
1319         self._assert_ready()
1320         return self._value
1321
1322     def __bool__(self):
1323         self._assert_ready()
1324         return self._value
1325
1326     def __eq__(self, their):
1327         if isinstance(their, bool):
1328             return self._value == their
1329         if not issubclass(their.__class__, Boolean):
1330             return False
1331         return (
1332             self._value == their._value and
1333             self.tag == their.tag and
1334             self._expl == their._expl
1335         )
1336
1337     def __call__(
1338             self,
1339             value=None,
1340             impl=None,
1341             expl=None,
1342             default=None,
1343             optional=None,
1344     ):
1345         return self.__class__(
1346             value=value,
1347             impl=self.tag if impl is None else impl,
1348             expl=self._expl if expl is None else expl,
1349             default=self.default if default is None else default,
1350             optional=self.optional if optional is None else optional,
1351         )
1352
1353     def _encode(self):
1354         self._assert_ready()
1355         return b"".join((
1356             self.tag,
1357             len_encode(1),
1358             (b"\xFF" if self._value else b"\x00"),
1359         ))
1360
1361     def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1362         try:
1363             t, _, lv = tag_strip(tlv)
1364         except DecodeError as err:
1365             raise err.__class__(
1366                 msg=err.msg,
1367                 klass=self.__class__,
1368                 decode_path=decode_path,
1369                 offset=offset,
1370             )
1371         if t != self.tag:
1372             raise TagMismatch(
1373                 klass=self.__class__,
1374                 decode_path=decode_path,
1375                 offset=offset,
1376             )
1377         if tag_only:
1378             return
1379         try:
1380             l, _, v = len_decode(lv)
1381         except DecodeError as err:
1382             raise err.__class__(
1383                 msg=err.msg,
1384                 klass=self.__class__,
1385                 decode_path=decode_path,
1386                 offset=offset,
1387             )
1388         if l != 1:
1389             raise InvalidLength(
1390                 "Boolean's length must be equal to 1",
1391                 klass=self.__class__,
1392                 decode_path=decode_path,
1393                 offset=offset,
1394             )
1395         if l > len(v):
1396             raise NotEnoughData(
1397                 "encoded length is longer than data",
1398                 klass=self.__class__,
1399                 decode_path=decode_path,
1400                 offset=offset,
1401             )
1402         first_octet = byte2int(v)
1403         bered = False
1404         if first_octet == 0:
1405             value = False
1406         elif first_octet == 0xFF:
1407             value = True
1408         elif ctx.get("bered", False):
1409             value = True
1410             bered = True
1411         else:
1412             raise DecodeError(
1413                 "unacceptable Boolean value",
1414                 klass=self.__class__,
1415                 decode_path=decode_path,
1416                 offset=offset,
1417             )
1418         obj = self.__class__(
1419             value=value,
1420             impl=self.tag,
1421             expl=self._expl,
1422             default=self.default,
1423             optional=self.optional,
1424             _decoded=(offset, 1, 1),
1425         )
1426         obj.bered = bered
1427         return obj, v[1:]
1428
1429     def __repr__(self):
1430         return pp_console_row(next(self.pps()))
1431
1432     def pps(self, decode_path=()):
1433         yield _pp(
1434             asn1_type_name=self.asn1_type_name,
1435             obj_name=self.__class__.__name__,
1436             decode_path=decode_path,
1437             value=str(self._value) if self.ready else None,
1438             optional=self.optional,
1439             default=self == self.default,
1440             impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1441             expl=None if self._expl is None else tag_decode(self._expl),
1442             offset=self.offset,
1443             tlen=self.tlen,
1444             llen=self.llen,
1445             vlen=self.vlen,
1446             expl_offset=self.expl_offset if self.expled else None,
1447             expl_tlen=self.expl_tlen if self.expled else None,
1448             expl_llen=self.expl_llen if self.expled else None,
1449             expl_vlen=self.expl_vlen if self.expled else None,
1450         )
1451
1452
1453 class Integer(Obj):
1454     """``INTEGER`` integer type
1455
1456     >>> b = Integer(-123)
1457     INTEGER -123
1458     >>> b == Integer(-123)
1459     True
1460     >>> int(b)
1461     -123
1462
1463     >>> Integer(2, bounds=(1, 3))
1464     INTEGER 2
1465     >>> Integer(5, bounds=(1, 3))
1466     Traceback (most recent call last):
1467     pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1468
1469     ::
1470
1471         class Version(Integer):
1472             schema = (
1473                 ("v1", 0),
1474                 ("v2", 1),
1475                 ("v3", 2),
1476             )
1477
1478     >>> v = Version("v1")
1479     Version INTEGER v1
1480     >>> int(v)
1481     0
1482     >>> v.named
1483     'v1'
1484     >>> v.specs
1485     {'v3': 2, 'v1': 0, 'v2': 1}
1486     """
1487     __slots__ = ("specs", "_bound_min", "_bound_max")
1488     tag_default = tag_encode(2)
1489     asn1_type_name = "INTEGER"
1490
1491     def __init__(
1492             self,
1493             value=None,
1494             bounds=None,
1495             impl=None,
1496             expl=None,
1497             default=None,
1498             optional=False,
1499             _specs=None,
1500             _decoded=(0, 0, 0),
1501     ):
1502         """
1503         :param value: set the value. Either integer type, named value
1504                       (if ``schema`` is specified in the class), or
1505                       :py:class:`pyderasn.Integer` object
1506         :param bounds: set ``(MIN, MAX)`` value constraint.
1507                        (-inf, +inf) by default
1508         :param bytes impl: override default tag with ``IMPLICIT`` one
1509         :param bytes expl: override default tag with ``EXPLICIT`` one
1510         :param default: set default value. Type same as in ``value``
1511         :param bool optional: is object ``OPTIONAL`` in sequence
1512         """
1513         super(Integer, self).__init__(impl, expl, default, optional, _decoded)
1514         self._value = value
1515         specs = getattr(self, "schema", {}) if _specs is None else _specs
1516         self.specs = specs if isinstance(specs, dict) else dict(specs)
1517         self._bound_min, self._bound_max = getattr(
1518             self,
1519             "bounds",
1520             (float("-inf"), float("+inf")),
1521         ) if bounds is None else bounds
1522         if value is not None:
1523             self._value = self._value_sanitize(value)
1524         if default is not None:
1525             default = self._value_sanitize(default)
1526             self.default = self.__class__(
1527                 value=default,
1528                 impl=self.tag,
1529                 expl=self._expl,
1530                 _specs=self.specs,
1531             )
1532             if self._value is None:
1533                 self._value = default
1534
1535     def _value_sanitize(self, value):
1536         if issubclass(value.__class__, Integer):
1537             value = value._value
1538         elif isinstance(value, integer_types):
1539             pass
1540         elif isinstance(value, str):
1541             value = self.specs.get(value)
1542             if value is None:
1543                 raise ObjUnknown("integer value: %s" % value)
1544         else:
1545             raise InvalidValueType((self.__class__, int, str))
1546         if not self._bound_min <= value <= self._bound_max:
1547             raise BoundsError(self._bound_min, value, self._bound_max)
1548         return value
1549
1550     @property
1551     def ready(self):
1552         return self._value is not None
1553
1554     def copy(self):
1555         obj = self.__class__(_specs=self.specs)
1556         obj._value = self._value
1557         obj._bound_min = self._bound_min
1558         obj._bound_max = self._bound_max
1559         obj.tag = self.tag
1560         obj._expl = self._expl
1561         obj.default = self.default
1562         obj.optional = self.optional
1563         obj.offset = self.offset
1564         obj.llen = self.llen
1565         obj.vlen = self.vlen
1566         return obj
1567
1568     def __int__(self):
1569         self._assert_ready()
1570         return int(self._value)
1571
1572     def __hash__(self):
1573         self._assert_ready()
1574         return hash(
1575             self.tag +
1576             bytes(self._expl or b"") +
1577             str(self._value).encode("ascii"),
1578         )
1579
1580     def __eq__(self, their):
1581         if isinstance(their, integer_types):
1582             return self._value == their
1583         if not issubclass(their.__class__, Integer):
1584             return False
1585         return (
1586             self._value == their._value and
1587             self.tag == their.tag and
1588             self._expl == their._expl
1589         )
1590
1591     def __lt__(self, their):
1592         return self._value < their._value
1593
1594     @property
1595     def named(self):
1596         for name, value in self.specs.items():
1597             if value == self._value:
1598                 return name
1599
1600     def __call__(
1601             self,
1602             value=None,
1603             bounds=None,
1604             impl=None,
1605             expl=None,
1606             default=None,
1607             optional=None,
1608     ):
1609         return self.__class__(
1610             value=value,
1611             bounds=(
1612                 (self._bound_min, self._bound_max)
1613                 if bounds is None else bounds
1614             ),
1615             impl=self.tag if impl is None else impl,
1616             expl=self._expl if expl is None else expl,
1617             default=self.default if default is None else default,
1618             optional=self.optional if optional is None else optional,
1619             _specs=self.specs,
1620         )
1621
1622     def _encode(self):
1623         self._assert_ready()
1624         value = self._value
1625         if PY2:
1626             if value == 0:
1627                 octets = bytearray([0])
1628             elif value < 0:
1629                 value = -value
1630                 value -= 1
1631                 octets = bytearray()
1632                 while value > 0:
1633                     octets.append((value & 0xFF) ^ 0xFF)
1634                     value >>= 8
1635                 if len(octets) == 0 or octets[-1] & 0x80 == 0:
1636                     octets.append(0xFF)
1637             else:
1638                 octets = bytearray()
1639                 while value > 0:
1640                     octets.append(value & 0xFF)
1641                     value >>= 8
1642                 if octets[-1] & 0x80 > 0:
1643                     octets.append(0x00)
1644             octets.reverse()
1645             octets = bytes(octets)
1646         else:
1647             bytes_len = ceil(value.bit_length() / 8) or 1
1648             while True:
1649                 try:
1650                     octets = value.to_bytes(
1651                         bytes_len,
1652                         byteorder="big",
1653                         signed=True,
1654                     )
1655                 except OverflowError:
1656                     bytes_len += 1
1657                 else:
1658                     break
1659         return b"".join((self.tag, len_encode(len(octets)), octets))
1660
1661     def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1662         try:
1663             t, _, lv = tag_strip(tlv)
1664         except DecodeError as err:
1665             raise err.__class__(
1666                 msg=err.msg,
1667                 klass=self.__class__,
1668                 decode_path=decode_path,
1669                 offset=offset,
1670             )
1671         if t != self.tag:
1672             raise TagMismatch(
1673                 klass=self.__class__,
1674                 decode_path=decode_path,
1675                 offset=offset,
1676             )
1677         if tag_only:
1678             return
1679         try:
1680             l, llen, v = len_decode(lv)
1681         except DecodeError as err:
1682             raise err.__class__(
1683                 msg=err.msg,
1684                 klass=self.__class__,
1685                 decode_path=decode_path,
1686                 offset=offset,
1687             )
1688         if l > len(v):
1689             raise NotEnoughData(
1690                 "encoded length is longer than data",
1691                 klass=self.__class__,
1692                 decode_path=decode_path,
1693                 offset=offset,
1694             )
1695         if l == 0:
1696             raise NotEnoughData(
1697                 "zero length",
1698                 klass=self.__class__,
1699                 decode_path=decode_path,
1700                 offset=offset,
1701             )
1702         v, tail = v[:l], v[l:]
1703         first_octet = byte2int(v)
1704         if l > 1:
1705             second_octet = byte2int(v[1:])
1706             if (
1707                     ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
1708                     ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
1709             ):
1710                 raise DecodeError(
1711                     "non normalized integer",
1712                     klass=self.__class__,
1713                     decode_path=decode_path,
1714                     offset=offset,
1715                 )
1716         if PY2:
1717             value = 0
1718             if first_octet & 0x80 > 0:
1719                 octets = bytearray()
1720                 for octet in bytearray(v):
1721                     octets.append(octet ^ 0xFF)
1722                 for octet in octets:
1723                     value = (value << 8) | octet
1724                 value += 1
1725                 value = -value
1726             else:
1727                 for octet in bytearray(v):
1728                     value = (value << 8) | octet
1729         else:
1730             value = int.from_bytes(v, byteorder="big", signed=True)
1731         try:
1732             obj = self.__class__(
1733                 value=value,
1734                 bounds=(self._bound_min, self._bound_max),
1735                 impl=self.tag,
1736                 expl=self._expl,
1737                 default=self.default,
1738                 optional=self.optional,
1739                 _specs=self.specs,
1740                 _decoded=(offset, llen, l),
1741             )
1742         except BoundsError as err:
1743             raise DecodeError(
1744                 msg=str(err),
1745                 klass=self.__class__,
1746                 decode_path=decode_path,
1747                 offset=offset,
1748             )
1749         return obj, tail
1750
1751     def __repr__(self):
1752         return pp_console_row(next(self.pps()))
1753
1754     def pps(self, decode_path=()):
1755         yield _pp(
1756             asn1_type_name=self.asn1_type_name,
1757             obj_name=self.__class__.__name__,
1758             decode_path=decode_path,
1759             value=(self.named or str(self._value)) if self.ready else None,
1760             optional=self.optional,
1761             default=self == self.default,
1762             impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1763             expl=None if self._expl is None else tag_decode(self._expl),
1764             offset=self.offset,
1765             tlen=self.tlen,
1766             llen=self.llen,
1767             vlen=self.vlen,
1768             expl_offset=self.expl_offset if self.expled else None,
1769             expl_tlen=self.expl_tlen if self.expled else None,
1770             expl_llen=self.expl_llen if self.expled else None,
1771             expl_vlen=self.expl_vlen if self.expled else None,
1772         )
1773
1774
1775 class BitString(Obj):
1776     """``BIT STRING`` bit string type
1777
1778     >>> BitString(b"hello world")
1779     BIT STRING 88 bits 68656c6c6f20776f726c64
1780     >>> bytes(b)
1781     b'hello world'
1782     >>> b == b"hello world"
1783     True
1784     >>> b.bit_len
1785     88
1786
1787     >>> b = BitString("'010110000000'B")
1788     BIT STRING 12 bits 5800
1789     >>> b.bit_len
1790     12
1791     >>> b[0], b[1], b[2], b[3]
1792     (False, True, False, True)
1793     >>> b[1000]
1794     False
1795     >>> [v for v in b]
1796     [False, True, False, True, True, False, False, False, False, False, False, False]
1797
1798     ::
1799
1800         class KeyUsage(BitString):
1801             schema = (
1802                 ("digitalSignature", 0),
1803                 ("nonRepudiation", 1),
1804                 ("keyEncipherment", 2),
1805             )
1806
1807     >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
1808     KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
1809     >>> b.named
1810     ['nonRepudiation', 'keyEncipherment']
1811     >>> b.specs
1812     {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
1813     """
1814     __slots__ = ("specs", "defined")
1815     tag_default = tag_encode(3)
1816     asn1_type_name = "BIT STRING"
1817
1818     def __init__(
1819             self,
1820             value=None,
1821             impl=None,
1822             expl=None,
1823             default=None,
1824             optional=False,
1825             _specs=None,
1826             _decoded=(0, 0, 0),
1827     ):
1828         """
1829         :param value: set the value. Either binary type, tuple of named
1830                       values (if ``schema`` is specified in the class),
1831                       string in ``'XXX...'B`` form, or
1832                       :py:class:`pyderasn.BitString` object
1833         :param bytes impl: override default tag with ``IMPLICIT`` one
1834         :param bytes expl: override default tag with ``EXPLICIT`` one
1835         :param default: set default value. Type same as in ``value``
1836         :param bool optional: is object ``OPTIONAL`` in sequence
1837         """
1838         super(BitString, self).__init__(impl, expl, default, optional, _decoded)
1839         specs = getattr(self, "schema", {}) if _specs is None else _specs
1840         self.specs = specs if isinstance(specs, dict) else dict(specs)
1841         self._value = None if value is None else self._value_sanitize(value)
1842         if default is not None:
1843             default = self._value_sanitize(default)
1844             self.default = self.__class__(
1845                 value=default,
1846                 impl=self.tag,
1847                 expl=self._expl,
1848             )
1849             if value is None:
1850                 self._value = default
1851         self.defined = None
1852
1853     def _bits2octets(self, bits):
1854         if len(self.specs) > 0:
1855             bits = bits.rstrip("0")
1856         bit_len = len(bits)
1857         bits += "0" * ((8 - (bit_len % 8)) % 8)
1858         octets = bytearray(len(bits) // 8)
1859         for i in six_xrange(len(octets)):
1860             octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
1861         return bit_len, bytes(octets)
1862
1863     def _value_sanitize(self, value):
1864         if issubclass(value.__class__, BitString):
1865             return value._value
1866         if isinstance(value, (string_types, binary_type)):
1867             if (
1868                     isinstance(value, string_types) and
1869                     value.startswith("'") and
1870                     value.endswith("'B")
1871             ):
1872                 value = value[1:-2]
1873                 if not set(value) <= set(("0", "1")):
1874                     raise ValueError("B's coding contains unacceptable chars")
1875                 return self._bits2octets(value)
1876             elif isinstance(value, binary_type):
1877                 return (len(value) * 8, value)
1878             else:
1879                 raise InvalidValueType((
1880                     self.__class__,
1881                     string_types,
1882                     binary_type,
1883                 ))
1884         if isinstance(value, tuple):
1885             if (
1886                     len(value) == 2 and
1887                     isinstance(value[0], integer_types) and
1888                     isinstance(value[1], binary_type)
1889             ):
1890                 return value
1891             bits = []
1892             for name in value:
1893                 bit = self.specs.get(name)
1894                 if bit is None:
1895                     raise ObjUnknown("BitString value: %s" % name)
1896                 bits.append(bit)
1897             if len(bits) == 0:
1898                 return self._bits2octets("")
1899             bits = set(bits)
1900             return self._bits2octets("".join(
1901                 ("1" if bit in bits else "0")
1902                 for bit in six_xrange(max(bits) + 1)
1903             ))
1904         raise InvalidValueType((self.__class__, binary_type, string_types))
1905
1906     @property
1907     def ready(self):
1908         return self._value is not None
1909
1910     def copy(self):
1911         obj = self.__class__(_specs=self.specs)
1912         value = self._value
1913         if value is not None:
1914             value = (value[0], value[1])
1915         obj._value = value
1916         obj.tag = self.tag
1917         obj._expl = self._expl
1918         obj.default = self.default
1919         obj.optional = self.optional
1920         obj.offset = self.offset
1921         obj.llen = self.llen
1922         obj.vlen = self.vlen
1923         return obj
1924
1925     def __iter__(self):
1926         self._assert_ready()
1927         for i in six_xrange(self._value[0]):
1928             yield self[i]
1929
1930     @property
1931     def bit_len(self):
1932         self._assert_ready()
1933         return self._value[0]
1934
1935     def __bytes__(self):
1936         self._assert_ready()
1937         return self._value[1]
1938
1939     def __eq__(self, their):
1940         if isinstance(their, bytes):
1941             return self._value[1] == their
1942         if not issubclass(their.__class__, BitString):
1943             return False
1944         return (
1945             self._value == their._value and
1946             self.tag == their.tag and
1947             self._expl == their._expl
1948         )
1949
1950     @property
1951     def named(self):
1952         return [name for name, bit in self.specs.items() if self[bit]]
1953
1954     def __call__(
1955             self,
1956             value=None,
1957             impl=None,
1958             expl=None,
1959             default=None,
1960             optional=None,
1961     ):
1962         return self.__class__(
1963             value=value,
1964             impl=self.tag if impl is None else impl,
1965             expl=self._expl if expl is None else expl,
1966             default=self.default if default is None else default,
1967             optional=self.optional if optional is None else optional,
1968             _specs=self.specs,
1969         )
1970
1971     def __getitem__(self, key):
1972         if isinstance(key, int):
1973             bit_len, octets = self._value
1974             if key >= bit_len:
1975                 return False
1976             return (
1977                 byte2int(memoryview(octets)[key // 8:]) >>
1978                 (7 - (key % 8))
1979             ) & 1 == 1
1980         if isinstance(key, string_types):
1981             value = self.specs.get(key)
1982             if value is None:
1983                 raise ObjUnknown("BitString value: %s" % key)
1984             return self[value]
1985         raise InvalidValueType((int, str))
1986
1987     def _encode(self):
1988         self._assert_ready()
1989         bit_len, octets = self._value
1990         return b"".join((
1991             self.tag,
1992             len_encode(len(octets) + 1),
1993             int2byte((8 - bit_len % 8) % 8),
1994             octets,
1995         ))
1996
1997     def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1998         try:
1999             t, _, lv = tag_strip(tlv)
2000         except DecodeError as err:
2001             raise err.__class__(
2002                 msg=err.msg,
2003                 klass=self.__class__,
2004                 decode_path=decode_path,
2005                 offset=offset,
2006             )
2007         if t != self.tag:
2008             raise TagMismatch(
2009                 klass=self.__class__,
2010                 decode_path=decode_path,
2011                 offset=offset,
2012             )
2013         if tag_only:
2014             return
2015         try:
2016             l, llen, v = len_decode(lv)
2017         except DecodeError as err:
2018             raise err.__class__(
2019                 msg=err.msg,
2020                 klass=self.__class__,
2021                 decode_path=decode_path,
2022                 offset=offset,
2023             )
2024         if l > len(v):
2025             raise NotEnoughData(
2026                 "encoded length is longer than data",
2027                 klass=self.__class__,
2028                 decode_path=decode_path,
2029                 offset=offset,
2030             )
2031         if l == 0:
2032             raise NotEnoughData(
2033                 "zero length",
2034                 klass=self.__class__,
2035                 decode_path=decode_path,
2036                 offset=offset,
2037             )
2038         pad_size = byte2int(v)
2039         if l == 1 and pad_size != 0:
2040             raise DecodeError(
2041                 "invalid empty value",
2042                 klass=self.__class__,
2043                 decode_path=decode_path,
2044                 offset=offset,
2045             )
2046         if pad_size > 7:
2047             raise DecodeError(
2048                 "too big pad",
2049                 klass=self.__class__,
2050                 decode_path=decode_path,
2051                 offset=offset,
2052             )
2053         if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2054             raise DecodeError(
2055                 "invalid pad",
2056                 klass=self.__class__,
2057                 decode_path=decode_path,
2058                 offset=offset,
2059             )
2060         v, tail = v[:l], v[l:]
2061         obj = self.__class__(
2062             value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2063             impl=self.tag,
2064             expl=self._expl,
2065             default=self.default,
2066             optional=self.optional,
2067             _specs=self.specs,
2068             _decoded=(offset, llen, l),
2069         )
2070         return obj, tail
2071
2072     def __repr__(self):
2073         return pp_console_row(next(self.pps()))
2074
2075     def pps(self, decode_path=()):
2076         value = None
2077         blob = None
2078         if self.ready:
2079             bit_len, blob = self._value
2080             value = "%d bits" % bit_len
2081             if len(self.specs) > 0:
2082                 blob = tuple(self.named)
2083         yield _pp(
2084             asn1_type_name=self.asn1_type_name,
2085             obj_name=self.__class__.__name__,
2086             decode_path=decode_path,
2087             value=value,
2088             blob=blob,
2089             optional=self.optional,
2090             default=self == self.default,
2091             impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2092             expl=None if self._expl is None else tag_decode(self._expl),
2093             offset=self.offset,
2094             tlen=self.tlen,
2095             llen=self.llen,
2096             vlen=self.vlen,
2097             expl_offset=self.expl_offset if self.expled else None,
2098             expl_tlen=self.expl_tlen if self.expled else None,
2099             expl_llen=self.expl_llen if self.expled else None,
2100             expl_vlen=self.expl_vlen if self.expled else None,
2101         )
2102         defined_by, defined = self.defined or (None, None)
2103         if defined_by is not None:
2104             yield defined.pps(
2105                 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2106             )
2107
2108
2109 class OctetString(Obj):
2110     """``OCTET STRING`` binary string type
2111
2112     >>> s = OctetString(b"hello world")
2113     OCTET STRING 11 bytes 68656c6c6f20776f726c64
2114     >>> s == OctetString(b"hello world")
2115     True
2116     >>> bytes(s)
2117     b'hello world'
2118
2119     >>> OctetString(b"hello", bounds=(4, 4))
2120     Traceback (most recent call last):
2121     pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2122     >>> OctetString(b"hell", bounds=(4, 4))
2123     OCTET STRING 4 bytes 68656c6c
2124     """
2125     __slots__ = ("_bound_min", "_bound_max", "defined")
2126     tag_default = tag_encode(4)
2127     asn1_type_name = "OCTET STRING"
2128
2129     def __init__(
2130             self,
2131             value=None,
2132             bounds=None,
2133             impl=None,
2134             expl=None,
2135             default=None,
2136             optional=False,
2137             _decoded=(0, 0, 0),
2138     ):
2139         """
2140         :param value: set the value. Either binary type, or
2141                       :py:class:`pyderasn.OctetString` object
2142         :param bounds: set ``(MIN, MAX)`` value size constraint.
2143                        (-inf, +inf) by default
2144         :param bytes impl: override default tag with ``IMPLICIT`` one
2145         :param bytes expl: override default tag with ``EXPLICIT`` one
2146         :param default: set default value. Type same as in ``value``
2147         :param bool optional: is object ``OPTIONAL`` in sequence
2148         """
2149         super(OctetString, self).__init__(
2150             impl,
2151             expl,
2152             default,
2153             optional,
2154             _decoded,
2155         )
2156         self._value = value
2157         self._bound_min, self._bound_max = getattr(
2158             self,
2159             "bounds",
2160             (0, float("+inf")),
2161         ) if bounds is None else bounds
2162         if value is not None:
2163             self._value = self._value_sanitize(value)
2164         if default is not None:
2165             default = self._value_sanitize(default)
2166             self.default = self.__class__(
2167                 value=default,
2168                 impl=self.tag,
2169                 expl=self._expl,
2170             )
2171             if self._value is None:
2172                 self._value = default
2173         self.defined = None
2174
2175     def _value_sanitize(self, value):
2176         if issubclass(value.__class__, OctetString):
2177             value = value._value
2178         elif isinstance(value, binary_type):
2179             pass
2180         else:
2181             raise InvalidValueType((self.__class__, bytes))
2182         if not self._bound_min <= len(value) <= self._bound_max:
2183             raise BoundsError(self._bound_min, len(value), self._bound_max)
2184         return value
2185
2186     @property
2187     def ready(self):
2188         return self._value is not None
2189
2190     def copy(self):
2191         obj = self.__class__()
2192         obj._value = self._value
2193         obj._bound_min = self._bound_min
2194         obj._bound_max = self._bound_max
2195         obj.tag = self.tag
2196         obj._expl = self._expl
2197         obj.default = self.default
2198         obj.optional = self.optional
2199         obj.offset = self.offset
2200         obj.llen = self.llen
2201         obj.vlen = self.vlen
2202         return obj
2203
2204     def __bytes__(self):
2205         self._assert_ready()
2206         return self._value
2207
2208     def __eq__(self, their):
2209         if isinstance(their, binary_type):
2210             return self._value == their
2211         if not issubclass(their.__class__, OctetString):
2212             return False
2213         return (
2214             self._value == their._value and
2215             self.tag == their.tag and
2216             self._expl == their._expl
2217         )
2218
2219     def __lt__(self, their):
2220         return self._value < their._value
2221
2222     def __call__(
2223             self,
2224             value=None,
2225             bounds=None,
2226             impl=None,
2227             expl=None,
2228             default=None,
2229             optional=None,
2230     ):
2231         return self.__class__(
2232             value=value,
2233             bounds=(
2234                 (self._bound_min, self._bound_max)
2235                 if bounds is None else bounds
2236             ),
2237             impl=self.tag if impl is None else impl,
2238             expl=self._expl if expl is None else expl,
2239             default=self.default if default is None else default,
2240             optional=self.optional if optional is None else optional,
2241         )
2242
2243     def _encode(self):
2244         self._assert_ready()
2245         return b"".join((
2246             self.tag,
2247             len_encode(len(self._value)),
2248             self._value,
2249         ))
2250
2251     def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2252         try:
2253             t, _, lv = tag_strip(tlv)
2254         except DecodeError as err:
2255             raise err.__class__(
2256                 msg=err.msg,
2257                 klass=self.__class__,
2258                 decode_path=decode_path,
2259                 offset=offset,
2260             )
2261         if t != self.tag:
2262             raise TagMismatch(
2263                 klass=self.__class__,
2264                 decode_path=decode_path,
2265                 offset=offset,
2266             )
2267         if tag_only:
2268             return
2269         try:
2270             l, llen, v = len_decode(lv)
2271         except DecodeError as err:
2272             raise err.__class__(
2273                 msg=err.msg,
2274                 klass=self.__class__,
2275                 decode_path=decode_path,
2276                 offset=offset,
2277             )
2278         if l > len(v):
2279             raise NotEnoughData(
2280                 "encoded length is longer than data",
2281                 klass=self.__class__,
2282                 decode_path=decode_path,
2283                 offset=offset,
2284             )
2285         v, tail = v[:l], v[l:]
2286         try:
2287             obj = self.__class__(
2288                 value=v.tobytes(),
2289                 bounds=(self._bound_min, self._bound_max),
2290                 impl=self.tag,
2291                 expl=self._expl,
2292                 default=self.default,
2293                 optional=self.optional,
2294                 _decoded=(offset, llen, l),
2295             )
2296         except DecodeError as err:
2297             raise DecodeError(
2298                 msg=err.msg,
2299                 klass=self.__class__,
2300                 decode_path=decode_path,
2301                 offset=offset,
2302             )
2303         except BoundsError as err:
2304             raise DecodeError(
2305                 msg=str(err),
2306                 klass=self.__class__,
2307                 decode_path=decode_path,
2308                 offset=offset,
2309             )
2310         return obj, tail
2311
2312     def __repr__(self):
2313         return pp_console_row(next(self.pps()))
2314
2315     def pps(self, decode_path=()):
2316         yield _pp(
2317             asn1_type_name=self.asn1_type_name,
2318             obj_name=self.__class__.__name__,
2319             decode_path=decode_path,
2320             value=("%d bytes" % len(self._value)) if self.ready else None,
2321             blob=self._value if self.ready else None,
2322             optional=self.optional,
2323             default=self == self.default,
2324             impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2325             expl=None if self._expl is None else tag_decode(self._expl),
2326             offset=self.offset,
2327             tlen=self.tlen,
2328             llen=self.llen,
2329             vlen=self.vlen,
2330             expl_offset=self.expl_offset if self.expled else None,
2331             expl_tlen=self.expl_tlen if self.expled else None,
2332             expl_llen=self.expl_llen if self.expled else None,
2333             expl_vlen=self.expl_vlen if self.expled else None,
2334         )
2335         defined_by, defined = self.defined or (None, None)
2336         if defined_by is not None:
2337             yield defined.pps(
2338                 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2339             )
2340
2341
2342 class Null(Obj):
2343     """``NULL`` null object
2344
2345     >>> n = Null()
2346     NULL
2347     >>> n.ready
2348     True
2349     """
2350     __slots__ = ()
2351     tag_default = tag_encode(5)
2352     asn1_type_name = "NULL"
2353
2354     def __init__(
2355             self,
2356             value=None,  # unused, but Sequence passes it
2357             impl=None,
2358             expl=None,
2359             optional=False,
2360             _decoded=(0, 0, 0),
2361     ):
2362         """
2363         :param bytes impl: override default tag with ``IMPLICIT`` one
2364         :param bytes expl: override default tag with ``EXPLICIT`` one
2365         :param bool optional: is object ``OPTIONAL`` in sequence
2366         """
2367         super(Null, self).__init__(impl, expl, None, optional, _decoded)
2368         self.default = None
2369
2370     @property
2371     def ready(self):
2372         return True
2373
2374     def copy(self):
2375         obj = self.__class__()
2376         obj.tag = self.tag
2377         obj._expl = self._expl
2378         obj.default = self.default
2379         obj.optional = self.optional
2380         obj.offset = self.offset
2381         obj.llen = self.llen
2382         obj.vlen = self.vlen
2383         return obj
2384
2385     def __eq__(self, their):
2386         if not issubclass(their.__class__, Null):
2387             return False
2388         return (
2389             self.tag == their.tag and
2390             self._expl == their._expl
2391         )
2392
2393     def __call__(
2394             self,
2395             value=None,
2396             impl=None,
2397             expl=None,
2398             optional=None,
2399     ):
2400         return self.__class__(
2401             impl=self.tag if impl is None else impl,
2402             expl=self._expl if expl is None else expl,
2403             optional=self.optional if optional is None else optional,
2404         )
2405
2406     def _encode(self):
2407         return self.tag + len_encode(0)
2408
2409     def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2410         try:
2411             t, _, lv = tag_strip(tlv)
2412         except DecodeError as err:
2413             raise err.__class__(
2414                 msg=err.msg,
2415                 klass=self.__class__,
2416                 decode_path=decode_path,
2417                 offset=offset,
2418             )
2419         if t != self.tag:
2420             raise TagMismatch(
2421                 klass=self.__class__,
2422                 decode_path=decode_path,
2423                 offset=offset,
2424             )
2425         if tag_only:
2426             return
2427         try:
2428             l, _, v = len_decode(lv)
2429         except DecodeError as err:
2430             raise err.__class__(
2431                 msg=err.msg,
2432                 klass=self.__class__,
2433                 decode_path=decode_path,
2434                 offset=offset,
2435             )
2436         if l != 0:
2437             raise InvalidLength(
2438                 "Null must have zero length",
2439                 klass=self.__class__,
2440                 decode_path=decode_path,
2441                 offset=offset,
2442             )
2443         obj = self.__class__(
2444             impl=self.tag,
2445             expl=self._expl,
2446             optional=self.optional,
2447             _decoded=(offset, 1, 0),
2448         )
2449         return obj, v
2450
2451     def __repr__(self):
2452         return pp_console_row(next(self.pps()))
2453
2454     def pps(self, decode_path=()):
2455         yield _pp(
2456             asn1_type_name=self.asn1_type_name,
2457             obj_name=self.__class__.__name__,
2458             decode_path=decode_path,
2459             optional=self.optional,
2460             impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2461             expl=None if self._expl is None else tag_decode(self._expl),
2462             offset=self.offset,
2463             tlen=self.tlen,
2464             llen=self.llen,
2465             vlen=self.vlen,
2466             expl_offset=self.expl_offset if self.expled else None,
2467             expl_tlen=self.expl_tlen if self.expled else None,
2468             expl_llen=self.expl_llen if self.expled else None,
2469             expl_vlen=self.expl_vlen if self.expled else None,
2470         )
2471
2472
2473 class ObjectIdentifier(Obj):
2474     """``OBJECT IDENTIFIER`` OID type
2475
2476     >>> oid = ObjectIdentifier((1, 2, 3))
2477     OBJECT IDENTIFIER 1.2.3
2478     >>> oid == ObjectIdentifier("1.2.3")
2479     True
2480     >>> tuple(oid)
2481     (1, 2, 3)
2482     >>> str(oid)
2483     '1.2.3'
2484     >>> oid + (4, 5) + ObjectIdentifier("1.7")
2485     OBJECT IDENTIFIER 1.2.3.4.5.1.7
2486
2487     >>> str(ObjectIdentifier((3, 1)))
2488     Traceback (most recent call last):
2489     pyderasn.InvalidOID: unacceptable first arc value
2490     """
2491     __slots__ = ("defines",)
2492     tag_default = tag_encode(6)
2493     asn1_type_name = "OBJECT IDENTIFIER"
2494
2495     def __init__(
2496             self,
2497             value=None,
2498             defines=(),
2499             impl=None,
2500             expl=None,
2501             default=None,
2502             optional=False,
2503             _decoded=(0, 0, 0),
2504     ):
2505         """
2506         :param value: set the value. Either tuples of integers,
2507                       string of "."-concatenated integers, or
2508                       :py:class:`pyderasn.ObjectIdentifier` object
2509         :param defines: sequence of tuples. Each tuple has two elements.
2510                         First one is relative to current one decode
2511                         path, aiming to the field defined by that OID.
2512                         Read about relative path in
2513                         :py:func:`pyderasn.abs_decode_path`. Second
2514                         tuple element is ``{OID: pyderasn.Obj()}``
2515                         dictionary, mapping between current OID value
2516                         and structure applied to defined field.
2517                         :ref:`Read about DEFINED BY <definedby>`
2518         :param bytes impl: override default tag with ``IMPLICIT`` one
2519         :param bytes expl: override default tag with ``EXPLICIT`` one
2520         :param default: set default value. Type same as in ``value``
2521         :param bool optional: is object ``OPTIONAL`` in sequence
2522         """
2523         super(ObjectIdentifier, self).__init__(
2524             impl,
2525             expl,
2526             default,
2527             optional,
2528             _decoded,
2529         )
2530         self._value = value
2531         if value is not None:
2532             self._value = self._value_sanitize(value)
2533         if default is not None:
2534             default = self._value_sanitize(default)
2535             self.default = self.__class__(
2536                 value=default,
2537                 impl=self.tag,
2538                 expl=self._expl,
2539             )
2540             if self._value is None:
2541                 self._value = default
2542         self.defines = defines
2543
2544     def __add__(self, their):
2545         if isinstance(their, self.__class__):
2546             return self.__class__(self._value + their._value)
2547         if isinstance(their, tuple):
2548             return self.__class__(self._value + their)
2549         raise InvalidValueType((self.__class__, tuple))
2550
2551     def _value_sanitize(self, value):
2552         if issubclass(value.__class__, ObjectIdentifier):
2553             return value._value
2554         if isinstance(value, string_types):
2555             try:
2556                 value = tuple(int(arc) for arc in value.split("."))
2557             except ValueError:
2558                 raise InvalidOID("unacceptable arcs values")
2559         if isinstance(value, tuple):
2560             if len(value) < 2:
2561                 raise InvalidOID("less than 2 arcs")
2562             first_arc = value[0]
2563             if first_arc in (0, 1):
2564                 if not (0 <= value[1] <= 39):
2565                     raise InvalidOID("second arc is too wide")
2566             elif first_arc == 2:
2567                 pass
2568             else:
2569                 raise InvalidOID("unacceptable first arc value")
2570             return value
2571         raise InvalidValueType((self.__class__, str, tuple))
2572
2573     @property
2574     def ready(self):
2575         return self._value is not None
2576
2577     def copy(self):
2578         obj = self.__class__()
2579         obj._value = self._value
2580         obj.defines = self.defines
2581         obj.tag = self.tag
2582         obj._expl = self._expl
2583         obj.default = self.default
2584         obj.optional = self.optional
2585         obj.offset = self.offset
2586         obj.llen = self.llen
2587         obj.vlen = self.vlen
2588         return obj
2589
2590     def __iter__(self):
2591         self._assert_ready()
2592         return iter(self._value)
2593
2594     def __str__(self):
2595         return ".".join(str(arc) for arc in self._value or ())
2596
2597     def __hash__(self):
2598         self._assert_ready()
2599         return hash(
2600             self.tag +
2601             bytes(self._expl or b"") +
2602             str(self._value).encode("ascii"),
2603         )
2604
2605     def __eq__(self, their):
2606         if isinstance(their, tuple):
2607             return self._value == their
2608         if not issubclass(their.__class__, ObjectIdentifier):
2609             return False
2610         return (
2611             self.tag == their.tag and
2612             self._expl == their._expl and
2613             self._value == their._value
2614         )
2615
2616     def __lt__(self, their):
2617         return self._value < their._value
2618
2619     def __call__(
2620             self,
2621             value=None,
2622             defines=None,
2623             impl=None,
2624             expl=None,
2625             default=None,
2626             optional=None,
2627     ):
2628         return self.__class__(
2629             value=value,
2630             defines=self.defines if defines is None else defines,
2631             impl=self.tag if impl is None else impl,
2632             expl=self._expl if expl is None else expl,
2633             default=self.default if default is None else default,
2634             optional=self.optional if optional is None else optional,
2635         )
2636
2637     def _encode(self):
2638         self._assert_ready()
2639         value = self._value
2640         first_value = value[1]
2641         first_arc = value[0]
2642         if first_arc == 0:
2643             pass
2644         elif first_arc == 1:
2645             first_value += 40
2646         elif first_arc == 2:
2647             first_value += 80
2648         else:  # pragma: no cover
2649             raise RuntimeError("invalid arc is stored")
2650         octets = [zero_ended_encode(first_value)]
2651         for arc in value[2:]:
2652             octets.append(zero_ended_encode(arc))
2653         v = b"".join(octets)
2654         return b"".join((self.tag, len_encode(len(v)), v))
2655
2656     def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2657         try:
2658             t, _, lv = tag_strip(tlv)
2659         except DecodeError as err:
2660             raise err.__class__(
2661                 msg=err.msg,
2662                 klass=self.__class__,
2663                 decode_path=decode_path,
2664                 offset=offset,
2665             )
2666         if t != self.tag:
2667             raise TagMismatch(
2668                 klass=self.__class__,
2669                 decode_path=decode_path,
2670                 offset=offset,
2671             )
2672         if tag_only:
2673             return
2674         try:
2675             l, llen, v = len_decode(lv)
2676         except DecodeError as err:
2677             raise err.__class__(
2678                 msg=err.msg,
2679                 klass=self.__class__,
2680                 decode_path=decode_path,
2681                 offset=offset,
2682             )
2683         if l > len(v):
2684             raise NotEnoughData(
2685                 "encoded length is longer than data",
2686                 klass=self.__class__,
2687                 decode_path=decode_path,
2688                 offset=offset,
2689             )
2690         if l == 0:
2691             raise NotEnoughData(
2692                 "zero length",
2693                 klass=self.__class__,
2694                 decode_path=decode_path,
2695                 offset=offset,
2696             )
2697         v, tail = v[:l], v[l:]
2698         arcs = []
2699         while len(v) > 0:
2700             i = 0
2701             arc = 0
2702             while True:
2703                 octet = indexbytes(v, i)
2704                 arc = (arc << 7) | (octet & 0x7F)
2705                 if octet & 0x80 == 0:
2706                     arcs.append(arc)
2707                     v = v[i + 1:]
2708                     break
2709                 i += 1
2710                 if i == len(v):
2711                     raise DecodeError(
2712                         "unfinished OID",
2713                         klass=self.__class__,
2714                         decode_path=decode_path,
2715                         offset=offset,
2716                     )
2717         first_arc = 0
2718         second_arc = arcs[0]
2719         if 0 <= second_arc <= 39:
2720             first_arc = 0
2721         elif 40 <= second_arc <= 79:
2722             first_arc = 1
2723             second_arc -= 40
2724         else:
2725             first_arc = 2
2726             second_arc -= 80
2727         obj = self.__class__(
2728             value=tuple([first_arc, second_arc] + arcs[1:]),
2729             impl=self.tag,
2730             expl=self._expl,
2731             default=self.default,
2732             optional=self.optional,
2733             _decoded=(offset, llen, l),
2734         )
2735         return obj, tail
2736
2737     def __repr__(self):
2738         return pp_console_row(next(self.pps()))
2739
2740     def pps(self, decode_path=()):
2741         yield _pp(
2742             asn1_type_name=self.asn1_type_name,
2743             obj_name=self.__class__.__name__,
2744             decode_path=decode_path,
2745             value=str(self) if self.ready else None,
2746             optional=self.optional,
2747             default=self == self.default,
2748             impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2749             expl=None if self._expl is None else tag_decode(self._expl),
2750             offset=self.offset,
2751             tlen=self.tlen,
2752             llen=self.llen,
2753             vlen=self.vlen,
2754             expl_offset=self.expl_offset if self.expled else None,
2755             expl_tlen=self.expl_tlen if self.expled else None,
2756             expl_llen=self.expl_llen if self.expled else None,
2757             expl_vlen=self.expl_vlen if self.expled else None,
2758         )
2759
2760
2761 class Enumerated(Integer):
2762     """``ENUMERATED`` integer type
2763
2764     This type is identical to :py:class:`pyderasn.Integer`, but requires
2765     schema to be specified and does not accept values missing from it.
2766     """
2767     __slots__ = ()
2768     tag_default = tag_encode(10)
2769     asn1_type_name = "ENUMERATED"
2770
2771     def __init__(
2772             self,
2773             value=None,
2774             impl=None,
2775             expl=None,
2776             default=None,
2777             optional=False,
2778             _specs=None,
2779             _decoded=(0, 0, 0),
2780             bounds=None,  # dummy argument, workability for Integer.decode
2781     ):
2782         super(Enumerated, self).__init__(
2783             value=value,
2784             impl=impl,
2785             expl=expl,
2786             default=default,
2787             optional=optional,
2788             _specs=_specs,
2789             _decoded=_decoded,
2790         )
2791         if len(self.specs) == 0:
2792             raise ValueError("schema must be specified")
2793
2794     def _value_sanitize(self, value):
2795         if isinstance(value, self.__class__):
2796             value = value._value
2797         elif isinstance(value, integer_types):
2798             if value not in list(self.specs.values()):
2799                 raise DecodeError(
2800                     "unknown integer value: %s" % value,
2801                     klass=self.__class__,
2802                 )
2803         elif isinstance(value, string_types):
2804             value = self.specs.get(value)
2805             if value is None:
2806                 raise ObjUnknown("integer value: %s" % value)
2807         else:
2808             raise InvalidValueType((self.__class__, int, str))
2809         return value
2810
2811     def copy(self):
2812         obj = self.__class__(_specs=self.specs)
2813         obj._value = self._value
2814         obj._bound_min = self._bound_min
2815         obj._bound_max = self._bound_max
2816         obj.tag = self.tag
2817         obj._expl = self._expl
2818         obj.default = self.default
2819         obj.optional = self.optional
2820         obj.offset = self.offset
2821         obj.llen = self.llen
2822         obj.vlen = self.vlen
2823         return obj
2824
2825     def __call__(
2826             self,
2827             value=None,
2828             impl=None,
2829             expl=None,
2830             default=None,
2831             optional=None,
2832             _specs=None,
2833     ):
2834         return self.__class__(
2835             value=value,
2836             impl=self.tag if impl is None else impl,
2837             expl=self._expl if expl is None else expl,
2838             default=self.default if default is None else default,
2839             optional=self.optional if optional is None else optional,
2840             _specs=self.specs,
2841         )
2842
2843
2844 class CommonString(OctetString):
2845     """Common class for all strings
2846
2847     Everything resembles :py:class:`pyderasn.OctetString`, except
2848     ability to deal with unicode text strings.
2849
2850     >>> hexenc("привет Ð¼Ð¸Ñ€".encode("utf-8"))
2851     'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
2852     >>> UTF8String("привет Ð¼Ð¸Ñ€") == UTF8String(hexdec("d0...80"))
2853     True
2854     >>> s = UTF8String("привет Ð¼Ð¸Ñ€")
2855     UTF8String UTF8String Ð¿Ñ€Ð¸Ð²ÐµÑ‚ Ð¼Ð¸Ñ€
2856     >>> str(s)
2857     'привет Ð¼Ð¸Ñ€'
2858     >>> hexenc(bytes(s))
2859     'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
2860
2861     >>> PrintableString("привет Ð¼Ð¸Ñ€")
2862     Traceback (most recent call last):
2863     pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
2864
2865     >>> BMPString("ада", bounds=(2, 2))
2866     Traceback (most recent call last):
2867     pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
2868     >>> s = BMPString("ад", bounds=(2, 2))
2869     >>> s.encoding
2870     'utf-16-be'
2871     >>> hexenc(bytes(s))
2872     '04300434'
2873
2874     .. list-table::
2875        :header-rows: 1
2876
2877        * - Class
2878          - Text Encoding
2879        * - :py:class:`pyderasn.UTF8String`
2880          - utf-8
2881        * - :py:class:`pyderasn.NumericString`
2882          - ascii
2883        * - :py:class:`pyderasn.PrintableString`
2884          - ascii
2885        * - :py:class:`pyderasn.TeletexString`
2886          - ascii
2887        * - :py:class:`pyderasn.T61String`
2888          - ascii
2889        * - :py:class:`pyderasn.VideotexString`
2890          - iso-8859-1
2891        * - :py:class:`pyderasn.IA5String`
2892          - ascii
2893        * - :py:class:`pyderasn.GraphicString`
2894          - iso-8859-1
2895        * - :py:class:`pyderasn.VisibleString`
2896          - ascii
2897        * - :py:class:`pyderasn.ISO646String`
2898          - ascii
2899        * - :py:class:`pyderasn.GeneralString`
2900          - iso-8859-1
2901        * - :py:class:`pyderasn.UniversalString`
2902          - utf-32-be
2903        * - :py:class:`pyderasn.BMPString`
2904          - utf-16-be
2905     """
2906     __slots__ = ("encoding",)
2907
2908     def _value_sanitize(self, value):
2909         value_raw = None
2910         value_decoded = None
2911         if isinstance(value, self.__class__):
2912             value_raw = value._value
2913         elif isinstance(value, text_type):
2914             value_decoded = value
2915         elif isinstance(value, binary_type):
2916             value_raw = value
2917         else:
2918             raise InvalidValueType((self.__class__, text_type, binary_type))
2919         try:
2920             value_raw = (
2921                 value_decoded.encode(self.encoding)
2922                 if value_raw is None else value_raw
2923             )
2924             value_decoded = (
2925                 value_raw.decode(self.encoding)
2926                 if value_decoded is None else value_decoded
2927             )
2928         except (UnicodeEncodeError, UnicodeDecodeError) as err:
2929             raise DecodeError(str(err))
2930         if not self._bound_min <= len(value_decoded) <= self._bound_max:
2931             raise BoundsError(
2932                 self._bound_min,
2933                 len(value_decoded),
2934                 self._bound_max,
2935             )
2936         return value_raw
2937
2938     def __eq__(self, their):
2939         if isinstance(their, binary_type):
2940             return self._value == their
2941         if isinstance(their, text_type):
2942             return self._value == their.encode(self.encoding)
2943         if not isinstance(their, self.__class__):
2944             return False
2945         return (
2946             self._value == their._value and
2947             self.tag == their.tag and
2948             self._expl == their._expl
2949         )
2950
2951     def __unicode__(self):
2952         if self.ready:
2953             return self._value.decode(self.encoding)
2954         return text_type(self._value)
2955
2956     def __repr__(self):
2957         return pp_console_row(next(self.pps(no_unicode=PY2)))
2958
2959     def pps(self, decode_path=(), no_unicode=False):
2960         value = None
2961         if self.ready:
2962             value = hexenc(bytes(self)) if no_unicode else self.__unicode__()
2963         yield _pp(
2964             asn1_type_name=self.asn1_type_name,
2965             obj_name=self.__class__.__name__,
2966             decode_path=decode_path,
2967             value=value,
2968             optional=self.optional,
2969             default=self == self.default,
2970             impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2971             expl=None if self._expl is None else tag_decode(self._expl),
2972             offset=self.offset,
2973             tlen=self.tlen,
2974             llen=self.llen,
2975             vlen=self.vlen,
2976         )
2977
2978
2979 class UTF8String(CommonString):
2980     __slots__ = ()
2981     tag_default = tag_encode(12)
2982     encoding = "utf-8"
2983     asn1_type_name = "UTF8String"
2984
2985
2986 class NumericString(CommonString):
2987     __slots__ = ()
2988     tag_default = tag_encode(18)
2989     encoding = "ascii"
2990     asn1_type_name = "NumericString"
2991     allowable_chars = set(digits.encode("ascii"))
2992
2993     def _value_sanitize(self, value):
2994         value = super(NumericString, self)._value_sanitize(value)
2995         if not set(value) <= self.allowable_chars:
2996             raise DecodeError("non-numeric value")
2997         return value
2998
2999
3000 class PrintableString(CommonString):
3001     __slots__ = ()
3002     tag_default = tag_encode(19)
3003     encoding = "ascii"
3004     asn1_type_name = "PrintableString"
3005
3006
3007 class TeletexString(CommonString):
3008     __slots__ = ()
3009     tag_default = tag_encode(20)
3010     encoding = "ascii"
3011     asn1_type_name = "TeletexString"
3012
3013
3014 class T61String(TeletexString):
3015     __slots__ = ()
3016     asn1_type_name = "T61String"
3017
3018
3019 class VideotexString(CommonString):
3020     __slots__ = ()
3021     tag_default = tag_encode(21)
3022     encoding = "iso-8859-1"
3023     asn1_type_name = "VideotexString"
3024
3025
3026 class IA5String(CommonString):
3027     __slots__ = ()
3028     tag_default = tag_encode(22)
3029     encoding = "ascii"
3030     asn1_type_name = "IA5"
3031
3032
3033 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
3034 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
3035 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
3036
3037
3038 class UTCTime(CommonString):
3039     """``UTCTime`` datetime type
3040
3041     >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3042     UTCTime UTCTime 2017-09-30T22:07:50
3043     >>> str(t)
3044     '170930220750Z'
3045     >>> bytes(t)
3046     b'170930220750Z'
3047     >>> t.todatetime()
3048     datetime.datetime(2017, 9, 30, 22, 7, 50)
3049     >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
3050     datetime.datetime(1957, 9, 30, 22, 7, 50)
3051     """
3052     __slots__ = ()
3053     tag_default = tag_encode(23)
3054     encoding = "ascii"
3055     asn1_type_name = "UTCTime"
3056
3057     fmt = "%y%m%d%H%M%SZ"
3058
3059     def __init__(
3060             self,
3061             value=None,
3062             impl=None,
3063             expl=None,
3064             default=None,
3065             optional=False,
3066             _decoded=(0, 0, 0),
3067             bounds=None,  # dummy argument, workability for OctetString.decode
3068     ):
3069         """
3070         :param value: set the value. Either datetime type, or
3071                       :py:class:`pyderasn.UTCTime` object
3072         :param bytes impl: override default tag with ``IMPLICIT`` one
3073         :param bytes expl: override default tag with ``EXPLICIT`` one
3074         :param default: set default value. Type same as in ``value``
3075         :param bool optional: is object ``OPTIONAL`` in sequence
3076         """
3077         super(UTCTime, self).__init__(
3078             impl=impl,
3079             expl=expl,
3080             default=default,
3081             optional=optional,
3082             _decoded=_decoded,
3083         )
3084         self._value = value
3085         if value is not None:
3086             self._value = self._value_sanitize(value)
3087         if default is not None:
3088             default = self._value_sanitize(default)
3089             self.default = self.__class__(
3090                 value=default,
3091                 impl=self.tag,
3092                 expl=self._expl,
3093             )
3094             if self._value is None:
3095                 self._value = default
3096
3097     def _value_sanitize(self, value):
3098         if isinstance(value, self.__class__):
3099             return value._value
3100         if isinstance(value, datetime):
3101             return value.strftime(self.fmt).encode("ascii")
3102         if isinstance(value, binary_type):
3103             value_decoded = value.decode("ascii")
3104             if len(value_decoded) == LEN_YYMMDDHHMMSSZ:
3105                 try:
3106                     datetime.strptime(value_decoded, self.fmt)
3107                 except ValueError:
3108                     raise DecodeError("invalid UTCTime format")
3109                 return value
3110             else:
3111                 raise DecodeError("invalid UTCTime length")
3112         raise InvalidValueType((self.__class__, datetime))
3113
3114     def __eq__(self, their):
3115         if isinstance(their, binary_type):
3116             return self._value == their
3117         if isinstance(their, datetime):
3118             return self.todatetime() == their
3119         if not isinstance(their, self.__class__):
3120             return False
3121         return (
3122             self._value == their._value and
3123             self.tag == their.tag and
3124             self._expl == their._expl
3125         )
3126
3127     def todatetime(self):
3128         """Convert to datetime
3129
3130         :returns: datetime
3131
3132         Pay attention that UTCTime can not hold full year, so all years
3133         having < 50 years are treated as 20xx, 19xx otherwise, according
3134         to X.509 recomendation.
3135         """
3136         value = datetime.strptime(self._value.decode("ascii"), self.fmt)
3137         year = value.year % 100
3138         return datetime(
3139             year=(2000 + year) if year < 50 else (1900 + year),
3140             month=value.month,
3141             day=value.day,
3142             hour=value.hour,
3143             minute=value.minute,
3144             second=value.second,
3145         )
3146
3147     def __repr__(self):
3148         return pp_console_row(next(self.pps()))
3149
3150     def pps(self, decode_path=()):
3151         yield _pp(
3152             asn1_type_name=self.asn1_type_name,
3153             obj_name=self.__class__.__name__,
3154             decode_path=decode_path,
3155             value=self.todatetime().isoformat() if self.ready else None,
3156             optional=self.optional,
3157             default=self == self.default,
3158             impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3159             expl=None if self._expl is None else tag_decode(self._expl),
3160             offset=self.offset,
3161             tlen=self.tlen,
3162             llen=self.llen,
3163             vlen=self.vlen,
3164         )
3165
3166
3167 class GeneralizedTime(UTCTime):
3168     """``GeneralizedTime`` datetime type
3169
3170     This type is similar to :py:class:`pyderasn.UTCTime`.
3171
3172     >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3173     GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
3174     >>> str(t)
3175     '20170930220750.000123Z'
3176     >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
3177     GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
3178     """
3179     __slots__ = ()
3180     tag_default = tag_encode(24)
3181     asn1_type_name = "GeneralizedTime"
3182
3183     fmt = "%Y%m%d%H%M%SZ"
3184     fmt_ms = "%Y%m%d%H%M%S.%fZ"
3185
3186     def _value_sanitize(self, value):
3187         if isinstance(value, self.__class__):
3188             return value._value
3189         if isinstance(value, datetime):
3190             return value.strftime(
3191                 self.fmt_ms if value.microsecond > 0 else self.fmt
3192             ).encode("ascii")
3193         if isinstance(value, binary_type):
3194             value_decoded = value.decode("ascii")
3195             if len(value_decoded) == LEN_YYYYMMDDHHMMSSZ:
3196                 try:
3197                     datetime.strptime(value_decoded, self.fmt)
3198                 except ValueError:
3199                     raise DecodeError(
3200                         "invalid GeneralizedTime (without ms) format",
3201                     )
3202                 return value
3203             elif len(value_decoded) >= LEN_YYYYMMDDHHMMSSDMZ:
3204                 try:
3205                     datetime.strptime(value_decoded, self.fmt_ms)
3206                 except ValueError:
3207                     raise DecodeError(
3208                         "invalid GeneralizedTime (with ms) format",
3209                     )
3210                 return value
3211             else:
3212                 raise DecodeError(
3213                     "invalid GeneralizedTime length",
3214                     klass=self.__class__,
3215                 )
3216         raise InvalidValueType((self.__class__, datetime))
3217
3218     def todatetime(self):
3219         value = self._value.decode("ascii")
3220         if len(value) == LEN_YYYYMMDDHHMMSSZ:
3221             return datetime.strptime(value, self.fmt)
3222         return datetime.strptime(value, self.fmt_ms)
3223
3224
3225 class GraphicString(CommonString):
3226     __slots__ = ()
3227     tag_default = tag_encode(25)
3228     encoding = "iso-8859-1"
3229     asn1_type_name = "GraphicString"
3230
3231
3232 class VisibleString(CommonString):
3233     __slots__ = ()
3234     tag_default = tag_encode(26)
3235     encoding = "ascii"
3236     asn1_type_name = "VisibleString"
3237
3238
3239 class ISO646String(VisibleString):
3240     __slots__ = ()
3241     asn1_type_name = "ISO646String"
3242
3243
3244 class GeneralString(CommonString):
3245     __slots__ = ()
3246     tag_default = tag_encode(27)
3247     encoding = "iso-8859-1"
3248     asn1_type_name = "GeneralString"
3249
3250
3251 class UniversalString(CommonString):
3252     __slots__ = ()
3253     tag_default = tag_encode(28)
3254     encoding = "utf-32-be"
3255     asn1_type_name = "UniversalString"
3256
3257
3258 class BMPString(CommonString):
3259     __slots__ = ()
3260     tag_default = tag_encode(30)
3261     encoding = "utf-16-be"
3262     asn1_type_name = "BMPString"
3263
3264
3265 class Choice(Obj):
3266     """``CHOICE`` special type
3267
3268     ::
3269
3270         class GeneralName(Choice):
3271             schema = (
3272                 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
3273                 ("dNSName", IA5String(impl=tag_ctxp(2))),
3274             )
3275
3276     >>> gn = GeneralName()
3277     GeneralName CHOICE
3278     >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
3279     GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3280     >>> gn["dNSName"] = IA5String("bar.baz")
3281     GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
3282     >>> gn["rfc822Name"]
3283     None
3284     >>> gn["dNSName"]
3285     [2] IA5String IA5 bar.baz
3286     >>> gn.choice
3287     'dNSName'
3288     >>> gn.value == gn["dNSName"]
3289     True
3290     >>> gn.specs
3291     OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
3292
3293     >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
3294     GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3295     """
3296     __slots__ = ("specs",)
3297     tag_default = None
3298     asn1_type_name = "CHOICE"
3299
3300     def __init__(
3301             self,
3302             value=None,
3303             schema=None,
3304             impl=None,
3305             expl=None,
3306             default=None,
3307             optional=False,
3308             _decoded=(0, 0, 0),
3309     ):
3310         """
3311         :param value: set the value. Either ``(choice, value)`` tuple, or
3312                       :py:class:`pyderasn.Choice` object
3313         :param bytes impl: can not be set, do **not** use it
3314         :param bytes expl: override default tag with ``EXPLICIT`` one
3315         :param default: set default value. Type same as in ``value``
3316         :param bool optional: is object ``OPTIONAL`` in sequence
3317         """
3318         if impl is not None:
3319             raise ValueError("no implicit tag allowed for CHOICE")
3320         super(Choice, self).__init__(None, expl, default, optional, _decoded)
3321         if schema is None:
3322             schema = getattr(self, "schema", ())
3323         if len(schema) == 0:
3324             raise ValueError("schema must be specified")
3325         self.specs = (
3326             schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
3327         )
3328         self._value = None
3329         if value is not None:
3330             self._value = self._value_sanitize(value)
3331         if default is not None:
3332             default_value = self._value_sanitize(default)
3333             default_obj = self.__class__(impl=self.tag, expl=self._expl)
3334             default_obj.specs = self.specs
3335             default_obj._value = default_value
3336             self.default = default_obj
3337             if value is None:
3338                 self._value = default_obj.copy()._value
3339
3340     def _value_sanitize(self, value):
3341         if isinstance(value, self.__class__):
3342             return value._value
3343         if isinstance(value, tuple) and len(value) == 2:
3344             choice, obj = value
3345             spec = self.specs.get(choice)
3346             if spec is None:
3347                 raise ObjUnknown(choice)
3348             if not isinstance(obj, spec.__class__):
3349                 raise InvalidValueType((spec,))
3350             return (choice, spec(obj))
3351         raise InvalidValueType((self.__class__, tuple))
3352
3353     @property
3354     def ready(self):
3355         return self._value is not None and self._value[1].ready
3356
3357     def copy(self):
3358         obj = self.__class__(schema=self.specs)
3359         obj._expl = self._expl
3360         obj.default = self.default
3361         obj.optional = self.optional
3362         obj.offset = self.offset
3363         obj.llen = self.llen
3364         obj.vlen = self.vlen
3365         value = self._value
3366         if value is not None:
3367             obj._value = (value[0], value[1].copy())
3368         return obj
3369
3370     def __eq__(self, their):
3371         if isinstance(their, tuple) and len(their) == 2:
3372             return self._value == their
3373         if not isinstance(their, self.__class__):
3374             return False
3375         return (
3376             self.specs == their.specs and
3377             self._value == their._value
3378         )
3379
3380     def __call__(
3381             self,
3382             value=None,
3383             expl=None,
3384             default=None,
3385             optional=None,
3386     ):
3387         return self.__class__(
3388             value=value,
3389             schema=self.specs,
3390             expl=self._expl if expl is None else expl,
3391             default=self.default if default is None else default,
3392             optional=self.optional if optional is None else optional,
3393         )
3394
3395     @property
3396     def choice(self):
3397         self._assert_ready()
3398         return self._value[0]
3399
3400     @property
3401     def value(self):
3402         self._assert_ready()
3403         return self._value[1]
3404
3405     def __getitem__(self, key):
3406         if key not in self.specs:
3407             raise ObjUnknown(key)
3408         if self._value is None:
3409             return None
3410         choice, value = self._value
3411         if choice != key:
3412             return None
3413         return value
3414
3415     def __setitem__(self, key, value):
3416         spec = self.specs.get(key)
3417         if spec is None:
3418             raise ObjUnknown(key)
3419         if not isinstance(value, spec.__class__):
3420             raise InvalidValueType((spec.__class__,))
3421         self._value = (key, spec(value))
3422
3423     @property
3424     def tlen(self):
3425         return 0
3426
3427     @property
3428     def decoded(self):
3429         return self._value[1].decoded if self.ready else False
3430
3431     def _encode(self):
3432         self._assert_ready()
3433         return self._value[1].encode()
3434
3435     def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3436         for choice, spec in self.specs.items():
3437             sub_decode_path = decode_path + (choice,)
3438             try:
3439                 spec.decode(
3440                     tlv,
3441                     offset=offset,
3442                     leavemm=True,
3443                     decode_path=sub_decode_path,
3444                     ctx=ctx,
3445                     tag_only=True,
3446                 )
3447             except TagMismatch:
3448                 continue
3449             break
3450         else:
3451             raise TagMismatch(
3452                 klass=self.__class__,
3453                 decode_path=decode_path,
3454                 offset=offset,
3455             )
3456         if tag_only:
3457             return
3458         value, tail = spec.decode(
3459             tlv,
3460             offset=offset,
3461             leavemm=True,
3462             decode_path=sub_decode_path,
3463             ctx=ctx,
3464         )
3465         obj = self.__class__(
3466             schema=self.specs,
3467             expl=self._expl,
3468             default=self.default,
3469             optional=self.optional,
3470             _decoded=(offset, 0, value.tlvlen),
3471         )
3472         obj._value = (choice, value)
3473         return obj, tail
3474
3475     def __repr__(self):
3476         value = pp_console_row(next(self.pps()))
3477         if self.ready:
3478             value = "%s[%r]" % (value, self.value)
3479         return value
3480
3481     def pps(self, decode_path=()):
3482         yield _pp(
3483             asn1_type_name=self.asn1_type_name,
3484             obj_name=self.__class__.__name__,
3485             decode_path=decode_path,
3486             value=self.choice if self.ready else None,
3487             optional=self.optional,
3488             default=self == self.default,
3489             impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3490             expl=None if self._expl is None else tag_decode(self._expl),
3491             offset=self.offset,
3492             tlen=self.tlen,
3493             llen=self.llen,
3494             vlen=self.vlen,
3495         )
3496         if self.ready:
3497             yield self.value.pps(decode_path=decode_path + (self.choice,))
3498
3499
3500 class PrimitiveTypes(Choice):
3501     """Predefined ``CHOICE`` for all generic primitive types
3502
3503     It could be useful for general decoding of some unspecified values:
3504
3505     >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
3506     OCTET STRING 3 bytes 666f6f
3507     >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
3508     INTEGER 1193046
3509     """
3510     __slots__ = ()
3511     schema = tuple((klass.__name__, klass()) for klass in (
3512         Boolean,
3513         Integer,
3514         BitString,
3515         OctetString,
3516         Null,
3517         ObjectIdentifier,
3518         UTF8String,
3519         NumericString,
3520         PrintableString,
3521         TeletexString,
3522         VideotexString,
3523         IA5String,
3524         UTCTime,
3525         GeneralizedTime,
3526         GraphicString,
3527         VisibleString,
3528         ISO646String,
3529         GeneralString,
3530         UniversalString,
3531         BMPString,
3532     ))
3533
3534
3535 class Any(Obj):
3536     """``ANY`` special type
3537
3538     >>> Any(Integer(-123))
3539     ANY 020185
3540     >>> a = Any(OctetString(b"hello world").encode())
3541     ANY 040b68656c6c6f20776f726c64
3542     >>> hexenc(bytes(a))
3543     b'0x040x0bhello world'
3544     """
3545     __slots__ = ("defined",)
3546     tag_default = tag_encode(0)
3547     asn1_type_name = "ANY"
3548
3549     def __init__(
3550             self,
3551             value=None,
3552             expl=None,
3553             optional=False,
3554             _decoded=(0, 0, 0),
3555     ):
3556         """
3557         :param value: set the value. Either any kind of pyderasn's
3558                       **ready** object, or bytes. Pay attention that
3559                       **no** validation is performed is raw binary value
3560                       is valid TLV
3561         :param bytes expl: override default tag with ``EXPLICIT`` one
3562         :param bool optional: is object ``OPTIONAL`` in sequence
3563         """
3564         super(Any, self).__init__(None, expl, None, optional, _decoded)
3565         self._value = None if value is None else self._value_sanitize(value)
3566         self.defined = None
3567
3568     def _value_sanitize(self, value):
3569         if isinstance(value, self.__class__):
3570             return value._value
3571         if isinstance(value, Obj):
3572             return value.encode()
3573         if isinstance(value, binary_type):
3574             return value
3575         raise InvalidValueType((self.__class__, Obj, binary_type))
3576
3577     @property
3578     def ready(self):
3579         return self._value is not None
3580
3581     def copy(self):
3582         obj = self.__class__()
3583         obj._value = self._value
3584         obj.tag = self.tag
3585         obj._expl = self._expl
3586         obj.optional = self.optional
3587         obj.offset = self.offset
3588         obj.llen = self.llen
3589         obj.vlen = self.vlen
3590         return obj
3591
3592     def __eq__(self, their):
3593         if isinstance(their, binary_type):
3594             return self._value == their
3595         if issubclass(their.__class__, Any):
3596             return self._value == their._value
3597         return False
3598
3599     def __call__(
3600             self,
3601             value=None,
3602             expl=None,
3603             optional=None,
3604     ):
3605         return self.__class__(
3606             value=value,
3607             expl=self._expl if expl is None else expl,
3608             optional=self.optional if optional is None else optional,
3609         )
3610
3611     def __bytes__(self):
3612         self._assert_ready()
3613         return self._value
3614
3615     @property
3616     def tlen(self):
3617         return 0
3618
3619     def _encode(self):
3620         self._assert_ready()
3621         return self._value
3622
3623     def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3624         try:
3625             t, tlen, lv = tag_strip(tlv)
3626             l, llen, v = len_decode(lv)
3627         except DecodeError as err:
3628             raise err.__class__(
3629                 msg=err.msg,
3630                 klass=self.__class__,
3631                 decode_path=decode_path,
3632                 offset=offset,
3633             )
3634         if l > len(v):
3635             raise NotEnoughData(
3636                 "encoded length is longer than data",
3637                 klass=self.__class__,
3638                 decode_path=decode_path,
3639                 offset=offset,
3640             )
3641         tlvlen = tlen + llen + l
3642         v, tail = tlv[:tlvlen], v[l:]
3643         obj = self.__class__(
3644             value=v.tobytes(),
3645             expl=self._expl,
3646             optional=self.optional,
3647             _decoded=(offset, 0, tlvlen),
3648         )
3649         obj.tag = t
3650         return obj, tail
3651
3652     def __repr__(self):
3653         return pp_console_row(next(self.pps()))
3654
3655     def pps(self, decode_path=()):
3656         yield _pp(
3657             asn1_type_name=self.asn1_type_name,
3658             obj_name=self.__class__.__name__,
3659             decode_path=decode_path,
3660             blob=self._value if self.ready else None,
3661             optional=self.optional,
3662             default=self == self.default,
3663             impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3664             expl=None if self._expl is None else tag_decode(self._expl),
3665             offset=self.offset,
3666             tlen=self.tlen,
3667             llen=self.llen,
3668             vlen=self.vlen,
3669             expl_offset=self.expl_offset if self.expled else None,
3670             expl_tlen=self.expl_tlen if self.expled else None,
3671             expl_llen=self.expl_llen if self.expled else None,
3672             expl_vlen=self.expl_vlen if self.expled else None,
3673         )
3674         defined_by, defined = self.defined or (None, None)
3675         if defined_by is not None:
3676             yield defined.pps(
3677                 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3678             )
3679
3680
3681 ########################################################################
3682 # ASN.1 constructed types
3683 ########################################################################
3684
3685 def get_def_by_path(defines_by_path, sub_decode_path):
3686     """Get define by decode path
3687     """
3688     for path, define in defines_by_path:
3689         if len(path) != len(sub_decode_path):
3690             continue
3691         for p1, p2 in zip(path, sub_decode_path):
3692             if (p1 != any) and (p1 != p2):
3693                 break
3694         else:
3695             return define
3696
3697
3698 def abs_decode_path(decode_path, rel_path):
3699     """Create an absolute decode path from current and relative ones
3700
3701     :param decode_path: current decode path, starting point.
3702                         Tuple of strings
3703     :param rel_path: relative path to ``decode_path``. Tuple of strings.
3704                      If first tuple's element is "/", then treat it as
3705                      an absolute path, ignoring ``decode_path`` as
3706                      starting point. Also this tuple can contain ".."
3707                      elements, stripping the leading element from
3708                      ``decode_path``
3709
3710     >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
3711     ("foo", "bar", "baz", "whatever")
3712     >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
3713     ("foo", "whatever")
3714     >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
3715     ("baz", "whatever")
3716     """
3717     if rel_path[0] == "/":
3718         return rel_path[1:]
3719     if rel_path[0] == "..":
3720         return abs_decode_path(decode_path[:-1], rel_path[1:])
3721     return decode_path + rel_path
3722
3723
3724 class Sequence(Obj):
3725     """``SEQUENCE`` structure type
3726
3727     You have to make specification of sequence::
3728
3729         class Extension(Sequence):
3730             schema = (
3731                 ("extnID", ObjectIdentifier()),
3732                 ("critical", Boolean(default=False)),
3733                 ("extnValue", OctetString()),
3734             )
3735
3736     Then, you can work with it as with dictionary.
3737
3738     >>> ext = Extension()
3739     >>> Extension().specs
3740     OrderedDict([
3741         ('extnID', OBJECT IDENTIFIER),
3742         ('critical', BOOLEAN False OPTIONAL DEFAULT),
3743         ('extnValue', OCTET STRING),
3744     ])
3745     >>> ext["extnID"] = "1.2.3"
3746     Traceback (most recent call last):
3747     pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
3748     >>> ext["extnID"] = ObjectIdentifier("1.2.3")
3749
3750     You can determine if sequence is ready to be encoded:
3751
3752     >>> ext.ready
3753     False
3754     >>> ext.encode()
3755     Traceback (most recent call last):
3756     pyderasn.ObjNotReady: object is not ready: extnValue
3757     >>> ext["extnValue"] = OctetString(b"foobar")
3758     >>> ext.ready
3759     True
3760
3761     Value you want to assign, must have the same **type** as in
3762     corresponding specification, but it can have different tags,
3763     optional/default attributes -- they will be taken from specification
3764     automatically::
3765
3766         class TBSCertificate(Sequence):
3767             schema = (
3768                 ("version", Version(expl=tag_ctxc(0), default="v1")),
3769             [...]
3770
3771     >>> tbs = TBSCertificate()
3772     >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
3773
3774     Assign ``None`` to remove value from sequence.
3775
3776     You can set values in Sequence during its initialization:
3777
3778     >>> AlgorithmIdentifier((
3779         ("algorithm", ObjectIdentifier("1.2.3")),
3780         ("parameters", Any(Null()))
3781     ))
3782     AlgorithmIdentifier SEQUENCE[OBJECT IDENTIFIER 1.2.3, ANY 0500 OPTIONAL]
3783
3784     You can determine if value exists/set in the sequence and take its value:
3785
3786     >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
3787     (True, True, False)
3788     >>> ext["extnID"]
3789     OBJECT IDENTIFIER 1.2.3
3790
3791     But pay attention that if value has default, then it won't be (not
3792     in) in the sequence (because ``DEFAULT`` must not be encoded in
3793     DER), but you can read its value:
3794
3795     >>> "critical" in ext, ext["critical"]
3796     (False, BOOLEAN False)
3797     >>> ext["critical"] = Boolean(True)
3798     >>> "critical" in ext, ext["critical"]
3799     (True, BOOLEAN True)
3800
3801     All defaulted values are always optional.
3802
3803     .. _strict_default_existence_ctx:
3804
3805     .. warning::
3806
3807        When decoded DER contains defaulted value inside, then
3808        technically this is not valid DER encoding. But we allow and pass
3809        it **by default**. Of course reencoding of that kind of DER will
3810        result in different binary representation (validly without
3811        defaulted value inside). You can enable strict defaulted values
3812        existence validation by setting ``"strict_default_existence":
3813        True`` :ref:`context <ctx>` option -- decoding process will raise
3814        an exception if defaulted value is met.
3815
3816     Two sequences are equal if they have equal specification (schema),
3817     implicit/explicit tagging and the same values.
3818     """
3819     __slots__ = ("specs",)
3820     tag_default = tag_encode(form=TagFormConstructed, num=16)
3821     asn1_type_name = "SEQUENCE"
3822
3823     def __init__(
3824             self,
3825             value=None,
3826             schema=None,
3827             impl=None,
3828             expl=None,
3829             default=None,
3830             optional=False,
3831             _decoded=(0, 0, 0),
3832     ):
3833         super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
3834         if schema is None:
3835             schema = getattr(self, "schema", ())
3836         self.specs = (
3837             schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
3838         )
3839         self._value = {}
3840         if value is not None:
3841             if issubclass(value.__class__, Sequence):
3842                 self._value = value._value
3843             elif hasattr(value, "__iter__"):
3844                 for seq_key, seq_value in value:
3845                     self[seq_key] = seq_value
3846             else:
3847                 raise InvalidValueType((Sequence,))
3848         if default is not None:
3849             if not issubclass(default.__class__, Sequence):
3850                 raise InvalidValueType((Sequence,))
3851             default_value = default._value
3852             default_obj = self.__class__(impl=self.tag, expl=self._expl)
3853             default_obj.specs = self.specs
3854             default_obj._value = default_value
3855             self.default = default_obj
3856             if value is None:
3857                 self._value = default_obj.copy()._value
3858
3859     @property
3860     def ready(self):
3861         for name, spec in self.specs.items():
3862             value = self._value.get(name)
3863             if value is None:
3864                 if spec.optional:
3865                     continue
3866                 return False
3867             else:
3868                 if not value.ready:
3869                     return False
3870         return True
3871
3872     def copy(self):
3873         obj = self.__class__(schema=self.specs)
3874         obj.tag = self.tag
3875         obj._expl = self._expl
3876         obj.default = self.default
3877         obj.optional = self.optional
3878         obj.offset = self.offset
3879         obj.llen = self.llen
3880         obj.vlen = self.vlen
3881         obj._value = {k: v.copy() for k, v in self._value.items()}
3882         return obj
3883
3884     def __eq__(self, their):
3885         if not isinstance(their, self.__class__):
3886             return False
3887         return (
3888             self.specs == their.specs and
3889             self.tag == their.tag and
3890             self._expl == their._expl and
3891             self._value == their._value
3892         )
3893
3894     def __call__(
3895             self,
3896             value=None,
3897             impl=None,
3898             expl=None,
3899             default=None,
3900             optional=None,
3901     ):
3902         return self.__class__(
3903             value=value,
3904             schema=self.specs,
3905             impl=self.tag if impl is None else impl,
3906             expl=self._expl if expl is None else expl,
3907             default=self.default if default is None else default,
3908             optional=self.optional if optional is None else optional,
3909         )
3910
3911     def __contains__(self, key):
3912         return key in self._value
3913
3914     def __setitem__(self, key, value):
3915         spec = self.specs.get(key)
3916         if spec is None:
3917             raise ObjUnknown(key)
3918         if value is None:
3919             self._value.pop(key, None)
3920             return
3921         if not isinstance(value, spec.__class__):
3922             raise InvalidValueType((spec.__class__,))
3923         value = spec(value=value)
3924         if spec.default is not None and value == spec.default:
3925             self._value.pop(key, None)
3926             return
3927         self._value[key] = value
3928
3929     def __getitem__(self, key):
3930         value = self._value.get(key)
3931         if value is not None:
3932             return value
3933         spec = self.specs.get(key)
3934         if spec is None:
3935             raise ObjUnknown(key)
3936         if spec.default is not None:
3937             return spec.default
3938         return None
3939
3940     def _encoded_values(self):
3941         raws = []
3942         for name, spec in self.specs.items():
3943             value = self._value.get(name)
3944             if value is None:
3945                 if spec.optional:
3946                     continue
3947                 raise ObjNotReady(name)
3948             raws.append(value.encode())
3949         return raws
3950
3951     def _encode(self):
3952         v = b"".join(self._encoded_values())
3953         return b"".join((self.tag, len_encode(len(v)), v))
3954
3955     def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3956         try:
3957             t, tlen, lv = tag_strip(tlv)
3958         except DecodeError as err:
3959             raise err.__class__(
3960                 msg=err.msg,
3961                 klass=self.__class__,
3962                 decode_path=decode_path,
3963                 offset=offset,
3964             )
3965         if t != self.tag:
3966             raise TagMismatch(
3967                 klass=self.__class__,
3968                 decode_path=decode_path,
3969                 offset=offset,
3970             )
3971         if tag_only:
3972             return
3973         try:
3974             l, llen, v = len_decode(lv)
3975         except DecodeError as err:
3976             raise err.__class__(
3977                 msg=err.msg,
3978                 klass=self.__class__,
3979                 decode_path=decode_path,
3980                 offset=offset,
3981             )
3982         if l > len(v):
3983             raise NotEnoughData(
3984                 "encoded length is longer than data",
3985                 klass=self.__class__,
3986                 decode_path=decode_path,
3987                 offset=offset,
3988             )
3989         v, tail = v[:l], v[l:]
3990         sub_offset = offset + tlen + llen
3991         values = {}
3992         for name, spec in self.specs.items():
3993             if len(v) == 0 and spec.optional:
3994                 continue
3995             sub_decode_path = decode_path + (name,)
3996             try:
3997                 value, v_tail = spec.decode(
3998                     v,
3999                     sub_offset,
4000                     leavemm=True,
4001                     decode_path=sub_decode_path,
4002                     ctx=ctx,
4003                 )
4004             except TagMismatch:
4005                 if spec.optional:
4006                     continue
4007                 raise
4008
4009             defined = get_def_by_path(ctx.get("defines", ()), sub_decode_path)
4010             if defined is not None:
4011                 defined_by, defined_spec = defined
4012                 if issubclass(value.__class__, SequenceOf):
4013                     for i, _value in enumerate(value):
4014                         sub_sub_decode_path = sub_decode_path + (
4015                             str(i),
4016                             DecodePathDefBy(defined_by),
4017                         )
4018                         defined_value, defined_tail = defined_spec.decode(
4019                             memoryview(bytes(_value)),
4020                             sub_offset + (
4021                                 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4022                                 if value.expled else (value.tlen + value.llen)
4023                             ),
4024                             leavemm=True,
4025                             decode_path=sub_sub_decode_path,
4026                             ctx=ctx,
4027                         )
4028                         if len(defined_tail) > 0:
4029                             raise DecodeError(
4030                                 "remaining data",
4031                                 klass=self.__class__,
4032                                 decode_path=sub_sub_decode_path,
4033                                 offset=offset,
4034                             )
4035                         _value.defined = (defined_by, defined_value)
4036                 else:
4037                     defined_value, defined_tail = defined_spec.decode(
4038                         memoryview(bytes(value)),
4039                         sub_offset + (
4040                             (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4041                             if value.expled else (value.tlen + value.llen)
4042                         ),
4043                         leavemm=True,
4044                         decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4045                         ctx=ctx,
4046                     )
4047                     if len(defined_tail) > 0:
4048                         raise DecodeError(
4049                             "remaining data",
4050                             klass=self.__class__,
4051                             decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4052                             offset=offset,
4053                         )
4054                     value.defined = (defined_by, defined_value)
4055
4056             sub_offset += (value.expl_tlvlen if value.expled else value.tlvlen)
4057             v = v_tail
4058             if spec.default is not None and value == spec.default:
4059                 if ctx.get("strict_default_existence", False):
4060                     raise DecodeError(
4061                         "DEFAULT value met",
4062                         klass=self.__class__,
4063                         decode_path=sub_decode_path,
4064                         offset=sub_offset,
4065                     )
4066                 else:
4067                     continue
4068             values[name] = value
4069
4070             spec_defines = getattr(spec, "defines", ())
4071             if len(spec_defines) == 0:
4072                 defines_by_path = ctx.get("defines_by_path", ())
4073                 if len(defines_by_path) > 0:
4074                     spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
4075             if spec_defines is not None and len(spec_defines) > 0:
4076                 for rel_path, schema in spec_defines:
4077                     defined = schema.get(value, None)
4078                     if defined is not None:
4079                         ctx.setdefault("defines", []).append((
4080                             abs_decode_path(sub_decode_path[:-1], rel_path),
4081                             (value, defined),
4082                         ))
4083         if len(v) > 0:
4084             raise DecodeError(
4085                 "remaining data",
4086                 klass=self.__class__,
4087                 decode_path=decode_path,
4088                 offset=offset,
4089             )
4090         obj = self.__class__(
4091             schema=self.specs,
4092             impl=self.tag,
4093             expl=self._expl,
4094             default=self.default,
4095             optional=self.optional,
4096             _decoded=(offset, llen, l),
4097         )
4098         obj._value = values
4099         return obj, tail
4100
4101     def __repr__(self):
4102         value = pp_console_row(next(self.pps()))
4103         cols = []
4104         for name in self.specs:
4105             _value = self._value.get(name)
4106             if _value is None:
4107                 continue
4108             cols.append(repr(_value))
4109         return "%s[%s]" % (value, ", ".join(cols))
4110
4111     def pps(self, decode_path=()):
4112         yield _pp(
4113             asn1_type_name=self.asn1_type_name,
4114             obj_name=self.__class__.__name__,
4115             decode_path=decode_path,
4116             optional=self.optional,
4117             default=self == self.default,
4118             impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4119             expl=None if self._expl is None else tag_decode(self._expl),
4120             offset=self.offset,
4121             tlen=self.tlen,
4122             llen=self.llen,
4123             vlen=self.vlen,
4124             expl_offset=self.expl_offset if self.expled else None,
4125             expl_tlen=self.expl_tlen if self.expled else None,
4126             expl_llen=self.expl_llen if self.expled else None,
4127             expl_vlen=self.expl_vlen if self.expled else None,
4128         )
4129         for name in self.specs:
4130             value = self._value.get(name)
4131             if value is None:
4132                 continue
4133             yield value.pps(decode_path=decode_path + (name,))
4134
4135
4136 class Set(Sequence):
4137     """``SET`` structure type
4138
4139     Its usage is identical to :py:class:`pyderasn.Sequence`.
4140     """
4141     __slots__ = ()
4142     tag_default = tag_encode(form=TagFormConstructed, num=17)
4143     asn1_type_name = "SET"
4144
4145     def _encode(self):
4146         raws = self._encoded_values()
4147         raws.sort()
4148         v = b"".join(raws)
4149         return b"".join((self.tag, len_encode(len(v)), v))
4150
4151     def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4152         try:
4153             t, tlen, lv = tag_strip(tlv)
4154         except DecodeError as err:
4155             raise err.__class__(
4156                 msg=err.msg,
4157                 klass=self.__class__,
4158                 decode_path=decode_path,
4159                 offset=offset,
4160             )
4161         if t != self.tag:
4162             raise TagMismatch(
4163                 klass=self.__class__,
4164                 decode_path=decode_path,
4165                 offset=offset,
4166             )
4167         if tag_only:
4168             return
4169         try:
4170             l, llen, v = len_decode(lv)
4171         except DecodeError as err:
4172             raise err.__class__(
4173                 msg=err.msg,
4174                 klass=self.__class__,
4175                 decode_path=decode_path,
4176                 offset=offset,
4177             )
4178         if l > len(v):
4179             raise NotEnoughData(
4180                 "encoded length is longer than data",
4181                 klass=self.__class__,
4182                 offset=offset,
4183             )
4184         v, tail = v[:l], v[l:]
4185         sub_offset = offset + tlen + llen
4186         values = {}
4187         specs_items = self.specs.items
4188         while len(v) > 0:
4189             for name, spec in specs_items():
4190                 sub_decode_path = decode_path + (name,)
4191                 try:
4192                     spec.decode(
4193                         v,
4194                         sub_offset,
4195                         leavemm=True,
4196                         decode_path=sub_decode_path,
4197                         ctx=ctx,
4198                         tag_only=True,
4199                     )
4200                 except TagMismatch:
4201                     continue
4202                 break
4203             else:
4204                 raise TagMismatch(
4205                     klass=self.__class__,
4206                     decode_path=decode_path,
4207                     offset=offset,
4208                 )
4209             value, v_tail = spec.decode(
4210                 v,
4211                 sub_offset,
4212                 leavemm=True,
4213                 decode_path=sub_decode_path,
4214                 ctx=ctx,
4215             )
4216             sub_offset += (
4217                 value.expl_tlvlen if value.expled else value.tlvlen
4218             )
4219             v = v_tail
4220             if spec.default is None or value != spec.default:  # pragma: no cover
4221                 # SeqMixing.test_encoded_default_accepted covers that place
4222                 values[name] = value
4223         obj = self.__class__(
4224             schema=self.specs,
4225             impl=self.tag,
4226             expl=self._expl,
4227             default=self.default,
4228             optional=self.optional,
4229             _decoded=(offset, llen, l),
4230         )
4231         obj._value = values
4232         return obj, tail
4233
4234
4235 class SequenceOf(Obj):
4236     """``SEQUENCE OF`` sequence type
4237
4238     For that kind of type you must specify the object it will carry on
4239     (bounds are for example here, not required)::
4240
4241         class Ints(SequenceOf):
4242             schema = Integer()
4243             bounds = (0, 2)
4244
4245     >>> ints = Ints()
4246     >>> ints.append(Integer(123))
4247     >>> ints.append(Integer(234))
4248     >>> ints
4249     Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
4250     >>> [int(i) for i in ints]
4251     [123, 234]
4252     >>> ints.append(Integer(345))
4253     Traceback (most recent call last):
4254     pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
4255     >>> ints[1]
4256     INTEGER 234
4257     >>> ints[1] = Integer(345)
4258     >>> ints
4259     Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
4260
4261     Also you can initialize sequence with preinitialized values:
4262
4263     >>> ints = Ints([Integer(123), Integer(234)])
4264     """
4265     __slots__ = ("spec", "_bound_min", "_bound_max")
4266     tag_default = tag_encode(form=TagFormConstructed, num=16)
4267     asn1_type_name = "SEQUENCE OF"
4268
4269     def __init__(
4270             self,
4271             value=None,
4272             schema=None,
4273             bounds=None,
4274             impl=None,
4275             expl=None,
4276             default=None,
4277             optional=False,
4278             _decoded=(0, 0, 0),
4279     ):
4280         super(SequenceOf, self).__init__(
4281             impl,
4282             expl,
4283             default,
4284             optional,
4285             _decoded,
4286         )
4287         if schema is None:
4288             schema = getattr(self, "schema", None)
4289         if schema is None:
4290             raise ValueError("schema must be specified")
4291         self.spec = schema
4292         self._bound_min, self._bound_max = getattr(
4293             self,
4294             "bounds",
4295             (0, float("+inf")),
4296         ) if bounds is None else bounds
4297         self._value = []
4298         if value is not None:
4299             self._value = self._value_sanitize(value)
4300         if default is not None:
4301             default_value = self._value_sanitize(default)
4302             default_obj = self.__class__(
4303                 schema=schema,
4304                 impl=self.tag,
4305                 expl=self._expl,
4306             )
4307             default_obj._value = default_value
4308             self.default = default_obj
4309             if value is None:
4310                 self._value = default_obj.copy()._value
4311
4312     def _value_sanitize(self, value):
4313         if issubclass(value.__class__, SequenceOf):
4314             value = value._value
4315         elif hasattr(value, "__iter__"):
4316             value = list(value)
4317         else:
4318             raise InvalidValueType((self.__class__, iter))
4319         if not self._bound_min <= len(value) <= self._bound_max:
4320             raise BoundsError(self._bound_min, len(value), self._bound_max)
4321         for v in value:
4322             if not isinstance(v, self.spec.__class__):
4323                 raise InvalidValueType((self.spec.__class__,))
4324         return value
4325
4326     @property
4327     def ready(self):
4328         return all(v.ready for v in self._value)
4329
4330     def copy(self):
4331         obj = self.__class__(schema=self.spec)
4332         obj._bound_min = self._bound_min
4333         obj._bound_max = self._bound_max
4334         obj.tag = self.tag
4335         obj._expl = self._expl
4336         obj.default = self.default
4337         obj.optional = self.optional
4338         obj.offset = self.offset
4339         obj.llen = self.llen
4340         obj.vlen = self.vlen
4341         obj._value = [v.copy() for v in self._value]
4342         return obj
4343
4344     def __eq__(self, their):
4345         if isinstance(their, self.__class__):
4346             return (
4347                 self.spec == their.spec and
4348                 self.tag == their.tag and
4349                 self._expl == their._expl and
4350                 self._value == their._value
4351             )
4352         if hasattr(their, "__iter__"):
4353             return self._value == list(their)
4354         return False
4355
4356     def __call__(
4357             self,
4358             value=None,
4359             bounds=None,
4360             impl=None,
4361             expl=None,
4362             default=None,
4363             optional=None,
4364     ):
4365         return self.__class__(
4366             value=value,
4367             schema=self.spec,
4368             bounds=(
4369                 (self._bound_min, self._bound_max)
4370                 if bounds is None else bounds
4371             ),
4372             impl=self.tag if impl is None else impl,
4373             expl=self._expl if expl is None else expl,
4374             default=self.default if default is None else default,
4375             optional=self.optional if optional is None else optional,
4376         )
4377
4378     def __contains__(self, key):
4379         return key in self._value
4380
4381     def append(self, value):
4382         if not isinstance(value, self.spec.__class__):
4383             raise InvalidValueType((self.spec.__class__,))
4384         if len(self._value) + 1 > self._bound_max:
4385             raise BoundsError(
4386                 self._bound_min,
4387                 len(self._value) + 1,
4388                 self._bound_max,
4389             )
4390         self._value.append(value)
4391
4392     def __iter__(self):
4393         self._assert_ready()
4394         return iter(self._value)
4395
4396     def __len__(self):
4397         self._assert_ready()
4398         return len(self._value)
4399
4400     def __setitem__(self, key, value):
4401         if not isinstance(value, self.spec.__class__):
4402             raise InvalidValueType((self.spec.__class__,))
4403         self._value[key] = self.spec(value=value)
4404
4405     def __getitem__(self, key):
4406         return self._value[key]
4407
4408     def _encoded_values(self):
4409         return [v.encode() for v in self._value]
4410
4411     def _encode(self):
4412         v = b"".join(self._encoded_values())
4413         return b"".join((self.tag, len_encode(len(v)), v))
4414
4415     def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4416         try:
4417             t, tlen, lv = tag_strip(tlv)
4418         except DecodeError as err:
4419             raise err.__class__(
4420                 msg=err.msg,
4421                 klass=self.__class__,
4422                 decode_path=decode_path,
4423                 offset=offset,
4424             )
4425         if t != self.tag:
4426             raise TagMismatch(
4427                 klass=self.__class__,
4428                 decode_path=decode_path,
4429                 offset=offset,
4430             )
4431         if tag_only:
4432             return
4433         try:
4434             l, llen, v = len_decode(lv)
4435         except DecodeError as err:
4436             raise err.__class__(
4437                 msg=err.msg,
4438                 klass=self.__class__,
4439                 decode_path=decode_path,
4440                 offset=offset,
4441             )
4442         if l > len(v):
4443             raise NotEnoughData(
4444                 "encoded length is longer than data",
4445                 klass=self.__class__,
4446                 decode_path=decode_path,
4447                 offset=offset,
4448             )
4449         v, tail = v[:l], v[l:]
4450         sub_offset = offset + tlen + llen
4451         _value = []
4452         spec = self.spec
4453         while len(v) > 0:
4454             value, v_tail = spec.decode(
4455                 v,
4456                 sub_offset,
4457                 leavemm=True,
4458                 decode_path=decode_path + (str(len(_value)),),
4459                 ctx=ctx,
4460             )
4461             sub_offset += (value.expl_tlvlen if value.expled else value.tlvlen)
4462             v = v_tail
4463             _value.append(value)
4464         obj = self.__class__(
4465             value=_value,
4466             schema=spec,
4467             bounds=(self._bound_min, self._bound_max),
4468             impl=self.tag,
4469             expl=self._expl,
4470             default=self.default,
4471             optional=self.optional,
4472             _decoded=(offset, llen, l),
4473         )
4474         return obj, tail
4475
4476     def __repr__(self):
4477         return "%s[%s]" % (
4478             pp_console_row(next(self.pps())),
4479             ", ".join(repr(v) for v in self._value),
4480         )
4481
4482     def pps(self, decode_path=()):
4483         yield _pp(
4484             asn1_type_name=self.asn1_type_name,
4485             obj_name=self.__class__.__name__,
4486             decode_path=decode_path,
4487             optional=self.optional,
4488             default=self == self.default,
4489             impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4490             expl=None if self._expl is None else tag_decode(self._expl),
4491             offset=self.offset,
4492             tlen=self.tlen,
4493             llen=self.llen,
4494             vlen=self.vlen,
4495             expl_offset=self.expl_offset if self.expled else None,
4496             expl_tlen=self.expl_tlen if self.expled else None,
4497             expl_llen=self.expl_llen if self.expled else None,
4498             expl_vlen=self.expl_vlen if self.expled else None,
4499         )
4500         for i, value in enumerate(self._value):
4501             yield value.pps(decode_path=decode_path + (str(i),))
4502
4503
4504 class SetOf(SequenceOf):
4505     """``SET OF`` sequence type
4506
4507     Its usage is identical to :py:class:`pyderasn.SequenceOf`.
4508     """
4509     __slots__ = ()
4510     tag_default = tag_encode(form=TagFormConstructed, num=17)
4511     asn1_type_name = "SET OF"
4512
4513     def _encode(self):
4514         raws = self._encoded_values()
4515         raws.sort()
4516         v = b"".join(raws)
4517         return b"".join((self.tag, len_encode(len(v)), v))
4518
4519
4520 def obj_by_path(pypath):  # pragma: no cover
4521     """Import object specified as string Python path
4522
4523     Modules must be separated from classes/functions with ``:``.
4524
4525     >>> obj_by_path("foo.bar:Baz")
4526     <class 'foo.bar.Baz'>
4527     >>> obj_by_path("foo.bar:Baz.boo")
4528     <classmethod 'foo.bar.Baz.boo'>
4529     """
4530     mod, objs = pypath.rsplit(":", 1)
4531     from importlib import import_module
4532     obj = import_module(mod)
4533     for obj_name in objs.split("."):
4534         obj = getattr(obj, obj_name)
4535     return obj
4536
4537
4538 def generic_decoder():  # pragma: no cover
4539     # All of this below is a big hack with self references
4540     choice = PrimitiveTypes()
4541     choice.specs["SequenceOf"] = SequenceOf(schema=choice)
4542     choice.specs["SetOf"] = SetOf(schema=choice)
4543     for i in range(31):
4544         choice.specs["SequenceOf%d" % i] = SequenceOf(
4545             schema=choice,
4546             expl=tag_ctxc(i),
4547         )
4548     choice.specs["Any"] = Any()
4549
4550     # Class name equals to type name, to omit it from output
4551     class SEQUENCEOF(SequenceOf):
4552         __slots__ = ()
4553         schema = choice
4554
4555     def pprint_any(obj, oids=None, with_colours=False):
4556         def _pprint_pps(pps):
4557             for pp in pps:
4558                 if hasattr(pp, "_fields"):
4559                     if pp.asn1_type_name == Choice.asn1_type_name:
4560                         continue
4561                     pp_kwargs = pp._asdict()
4562                     pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
4563                     pp = _pp(**pp_kwargs)
4564                     yield pp_console_row(
4565                         pp,
4566                         oids=oids,
4567                         with_offsets=True,
4568                         with_blob=False,
4569                         with_colours=with_colours,
4570                     )
4571                     for row in pp_console_blob(pp):
4572                         yield row
4573                 else:
4574                     for row in _pprint_pps(pp):
4575                         yield row
4576         return "\n".join(_pprint_pps(obj.pps()))
4577     return SEQUENCEOF(), pprint_any
4578
4579
4580 def main():  # pragma: no cover
4581     import argparse
4582     parser = argparse.ArgumentParser(description="PyDERASN ASN.1 DER decoder")
4583     parser.add_argument(
4584         "--skip",
4585         type=int,
4586         default=0,
4587         help="Skip that number of bytes from the beginning",
4588     )
4589     parser.add_argument(
4590         "--oids",
4591         help="Python path to dictionary with OIDs",
4592     )
4593     parser.add_argument(
4594         "--schema",
4595         help="Python path to schema definition to use",
4596     )
4597     parser.add_argument(
4598         "--defines-by-path",
4599         help="Python path to decoder's defines_by_path",
4600     )
4601     parser.add_argument(
4602         "DERFile",
4603         type=argparse.FileType("rb"),
4604         help="Path to DER file you want to decode",
4605     )
4606     args = parser.parse_args()
4607     args.DERFile.seek(args.skip)
4608     der = memoryview(args.DERFile.read())
4609     args.DERFile.close()
4610     oids = obj_by_path(args.oids) if args.oids else {}
4611     if args.schema:
4612         schema = obj_by_path(args.schema)
4613         from functools import partial
4614         pprinter = partial(pprint, big_blobs=True)
4615     else:
4616         schema, pprinter = generic_decoder()
4617     obj, tail = schema().decode(
4618         der,
4619         ctx=(
4620             None if args.defines_by_path is None else
4621             {"defines_by_path": obj_by_path(args.defines_by_path)}
4622         ),
4623     )
4624     print(pprinter(
4625         obj,
4626         oids=oids,
4627         with_colours=True if environ.get("NO_COLOR") is None else False,
4628     ))
4629     if tail != b"":
4630         print("\nTrailing data: %s" % hexenc(tail))
4631
4632
4633 if __name__ == "__main__":
4634     main()