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