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