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