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>
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.
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.
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
20 This library allows you to marshal various structures in ASN.1 DER
21 format, unmarshal them in BER/CER/DER ones.
25 >>> Integer().decod(raw) == i
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`.
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
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
82 EXPLICIT tags always have **constructed** tag. PyDERASN does not
83 explicitly check correctness of schema input here.
87 Implicit tags have **primitive** (``tag_ctxp``) encoding for
92 >>> Integer(impl=tag_ctxp(1))
94 >>> Integer(expl=tag_ctxc(2))
97 Implicit tag is not explicitly shown.
99 Two objects of the same type, but with different implicit/explicit tags
102 You can get object's effective tag (either default or implicited) through
103 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
106 >>> tag_decode(tag_ctxc(123))
108 >>> klass, form, num = tag_decode(tag_ctxc(123))
109 >>> klass == TagClassContext
111 >>> form == TagFormConstructed
114 To determine if object has explicit tag, use ``expled`` boolean property
115 and ``expl_tag`` property, returning explicit tag's value.
120 Many objects in sequences could be ``OPTIONAL`` and could have
121 ``DEFAULT`` value. You can specify that object's property using
122 corresponding keyword arguments.
124 >>> Integer(optional=True, default=123)
125 INTEGER 123 OPTIONAL DEFAULT
127 Those specifications do not play any role in primitive value encoding,
128 but are taken into account when dealing with sequences holding them. For
129 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
132 class Version(Integer):
138 class TBSCertificate(Sequence):
140 ("version", Version(expl=tag_ctxc(0), default="v1")),
143 When default argument is used and value is not specified, then it equals
151 Some objects give ability to set value size constraints. This is either
152 possible integer value, or allowed length of various strings and
153 sequences. Constraints are set in the following way::
158 And values satisfaction is checked as: ``MIN <= X <= MAX``.
160 For simplicity you can also set bounds the following way::
162 bounded_x = X(bounds=(MIN, MAX))
164 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
170 All objects have ``ready`` boolean property, that tells if object is
171 ready to be encoded. If that kind of action is performed on unready
172 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
174 All objects are friendly to ``copy.copy()`` and copied objects can be
177 Also all objects can be safely ``pickle``-d, but pay attention that
178 pickling among different PyDERASN versions is prohibited.
185 Decoding is performed using :py:meth:`pyderasn.Obj.decode` method.
186 ``offset`` optional argument could be used to set initial object's
187 offset in the binary data, for convenience. It returns decoded object
188 and remaining unmarshalled data (tail). Internally all work is done on
189 ``memoryview(data)``, and you can leave returning tail as a memoryview,
190 by specifying ``leavemm=True`` argument.
192 Also note convenient :py:meth:`pyderasn.Obj.decod` method, that
193 immediately checks and raises if there is non-empty tail.
195 When object is decoded, ``decoded`` property is true and you can safely
196 use following properties:
198 * ``offset`` -- position including initial offset where object's tag starts
199 * ``tlen`` -- length of object's tag
200 * ``llen`` -- length of object's length value
201 * ``vlen`` -- length of object's value
202 * ``tlvlen`` -- length of the whole object
204 Pay attention that those values do **not** include anything related to
205 explicit tag. If you want to know information about it, then use:
207 * ``expled`` -- to know if explicit tag is set
208 * ``expl_offset`` (it is lesser than ``offset``)
211 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
212 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
214 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
217 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
224 You can specify so called context keyword argument during
225 :py:meth:`pyderasn.Obj.decode` invocation. It is dictionary containing
226 various options governing decoding process.
228 Currently available context options:
230 * :ref:`allow_default_values <allow_default_values_ctx>`
231 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
232 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
233 * :ref:`bered <bered_ctx>`
234 * :ref:`defines_by_path <defines_by_path_ctx>`
241 All objects have ``pps()`` method, that is a generator of
242 :py:class:`pyderasn.PP` namedtuple, holding various raw information
243 about the object. If ``pps`` is called on sequences, then all underlying
244 ``PP`` will be yielded.
246 You can use :py:func:`pyderasn.pp_console_row` function, converting
247 those ``PP`` to human readable string. Actually exactly it is used for
248 all object ``repr``. But it is easy to write custom formatters.
250 >>> from pyderasn import pprint
251 >>> encoded = Integer(-12345).encode()
252 >>> obj, tail = Integer().decode(encoded)
253 >>> print(pprint(obj))
254 0 [1,1, 2] INTEGER -12345
258 Example certificate::
260 >>> print(pprint(crt))
261 0 [1,3,1604] Certificate SEQUENCE
262 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
263 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
264 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
265 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
266 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
267 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
269 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
270 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
271 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
272 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
273 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
274 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
275 . . . . . . . 13:02:45:53
277 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
278 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
279 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
281 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
282 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
283 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
288 Let's parse that output, human::
290 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
291 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
292 0 1 2 3 4 5 6 7 8 9 10 11
296 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
302 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
308 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
313 Offset of the object, where its DER/BER encoding begins.
314 Pay attention that it does **not** include explicit tag.
316 If explicit tag exists, then this is its length (tag + encoded length).
318 Length of object's tag. For example CHOICE does not have its own tag,
321 Length of encoded length.
323 Length of encoded value.
325 Visual indentation to show the depth of object in the hierarchy.
327 Object's name inside SEQUENCE/CHOICE.
329 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
330 here. "IMPLICIT" is omitted.
332 Object's class name, if set. Omitted if it is just an ordinary simple
333 value (like with ``algorithm`` in example above).
337 Object's value, if set. Can consist of multiple words (like OCTET/BIT
338 STRINGs above). We see ``v3`` value in Version, because it is named.
339 ``rdnSequence`` is the choice of CHOICE type.
341 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
342 default one, specified in the schema.
344 Shows does object contains any kind of BER encoded data (possibly
345 Sequence holding BER-encoded underlying value).
347 Only applicable to BER encoded data. Indefinite length encoding mark.
349 Only applicable to BER encoded data. If object has BER-specific
350 encoding, then ``BER`` will be shown. It does not depend on indefinite
351 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
352 (and its derivatives), ``SET``, ``SET OF``, ``UTCTime``, ``GeneralizedTime``
360 ASN.1 structures often have ANY and OCTET STRING fields, that are
361 DEFINED BY some previously met ObjectIdentifier. This library provides
362 ability to specify mapping between some OID and field that must be
363 decoded with specific specification.
370 :py:class:`pyderasn.ObjectIdentifier` field inside
371 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
372 necessary for decoding structures. For example, CMS (:rfc:`5652`)
375 class ContentInfo(Sequence):
377 ("contentType", ContentType(defines=((("content",), {
378 id_digestedData: DigestedData(),
379 id_signedData: SignedData(),
381 ("content", Any(expl=tag_ctxc(0))),
384 ``contentType`` field tells that it defines that ``content`` must be
385 decoded with ``SignedData`` specification, if ``contentType`` equals to
386 ``id-signedData``. The same applies to ``DigestedData``. If
387 ``contentType`` contains unknown OID, then no automatic decoding is
390 You can specify multiple fields, that will be autodecoded -- that is why
391 ``defines`` kwarg is a sequence. You can specify defined field
392 relatively or absolutely to current decode path. For example ``defines``
393 for AlgorithmIdentifier of X.509's
394 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
398 id_ecPublicKey: ECParameters(),
399 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
401 (("..", "subjectPublicKey"), {
402 id_rsaEncryption: RSAPublicKey(),
403 id_GostR3410_2001: OctetString(),
407 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
408 autodecode its parameters inside SPKI's algorithm and its public key
411 Following types can be automatically decoded (DEFINED BY):
413 * :py:class:`pyderasn.Any`
414 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
415 * :py:class:`pyderasn.OctetString`
416 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
417 ``Any``/``BitString``/``OctetString``-s
419 When any of those fields is automatically decoded, then ``.defined``
420 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
421 was defined, ``value`` contains corresponding decoded value. For example
422 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
424 .. _defines_by_path_ctx:
426 defines_by_path context option
427 ______________________________
429 Sometimes you either can not or do not want to explicitly set *defines*
430 in the schema. You can dynamically apply those definitions when calling
431 ``.decode()`` method.
433 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
434 value must be sequence of following tuples::
436 (decode_path, defines)
438 where ``decode_path`` is a tuple holding so-called decode path to the
439 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
440 ``defines``, holding exactly the same value as accepted in its
441 :ref:`keyword argument <defines>`.
443 For example, again for CMS, you want to automatically decode
444 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
445 structures it may hold. Also, automatically decode ``controlSequence``
448 content_info = ContentInfo().decod(data, ctx={"defines_by_path": (
451 ((("content",), {id_signedData: SignedData()}),),
456 DecodePathDefBy(id_signedData),
461 id_cct_PKIData: PKIData(),
462 id_cct_PKIResponse: PKIResponse(),
468 DecodePathDefBy(id_signedData),
471 DecodePathDefBy(id_cct_PKIResponse),
477 id_cmc_recipientNonce: RecipientNonce(),
478 id_cmc_senderNonce: SenderNonce(),
479 id_cmc_statusInfoV2: CMCStatusInfoV2(),
480 id_cmc_transactionId: TransactionId(),
485 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
486 First function is useful for path construction when some automatic
487 decoding is already done. ``any`` means literally any value it meet --
488 useful for SEQUENCE/SET OF-s.
495 By default PyDERASN accepts only DER encoded data. It always encodes to
496 DER. But you can optionally enable BER decoding with setting ``bered``
497 :ref:`context <ctx>` argument to True. Indefinite lengths and
498 constructed primitive types should be parsed successfully.
500 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
501 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
502 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``,
503 ``UTCTime``, ``GeneralizedTime`` can contain it.
504 * If object has an indefinite length encoding, then its ``lenindef``
505 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
506 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
508 * If object has an indefinite length encoded explicit tag, then
509 ``expl_lenindef`` is set to True.
510 * If object has either any of BER-related encoding (explicit tag
511 indefinite length, object's indefinite length, BER-encoding) or any
512 underlying component has that kind of encoding, then ``bered``
513 attribute is set to True. For example SignedData CMS can have
514 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
515 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
517 EOC (end-of-contents) token's length is taken in advance in object's
520 .. _allow_expl_oob_ctx:
522 Allow explicit tag out-of-bound
523 -------------------------------
525 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
526 one value, more than one object. If you set ``allow_expl_oob`` context
527 option to True, then no error will be raised and that invalid encoding
528 will be silently further processed. But pay attention that offsets and
529 lengths will be invalid in that case.
533 This option should be used only for skipping some decode errors, just
534 to see the decoded structure somehow.
538 .. autoclass:: pyderasn.Obj
546 .. autoclass:: pyderasn.Boolean
551 .. autoclass:: pyderasn.Integer
552 :members: __init__, named
556 .. autoclass:: pyderasn.BitString
557 :members: __init__, bit_len, named
561 .. autoclass:: pyderasn.OctetString
566 .. autoclass:: pyderasn.Null
571 .. autoclass:: pyderasn.ObjectIdentifier
576 .. autoclass:: pyderasn.Enumerated
580 .. autoclass:: pyderasn.CommonString
584 .. autoclass:: pyderasn.NumericString
588 .. autoclass:: pyderasn.PrintableString
589 :members: __init__, allow_asterisk, allow_ampersand
593 .. autoclass:: pyderasn.UTCTime
594 :members: __init__, todatetime
598 .. autoclass:: pyderasn.GeneralizedTime
599 :members: __init__, todatetime
606 .. autoclass:: pyderasn.Choice
607 :members: __init__, choice, value
611 .. autoclass:: PrimitiveTypes
615 .. autoclass:: pyderasn.Any
623 .. autoclass:: pyderasn.Sequence
628 .. autoclass:: pyderasn.Set
633 .. autoclass:: pyderasn.SequenceOf
638 .. autoclass:: pyderasn.SetOf
644 .. autofunction:: pyderasn.abs_decode_path
645 .. autofunction:: pyderasn.colonize_hex
646 .. autofunction:: pyderasn.encode_cer
647 .. autofunction:: pyderasn.file_mmaped
648 .. autofunction:: pyderasn.hexenc
649 .. autofunction:: pyderasn.hexdec
650 .. autofunction:: pyderasn.tag_encode
651 .. autofunction:: pyderasn.tag_decode
652 .. autofunction:: pyderasn.tag_ctxp
653 .. autofunction:: pyderasn.tag_ctxc
654 .. autoclass:: pyderasn.DecodeError
656 .. autoclass:: pyderasn.NotEnoughData
657 .. autoclass:: pyderasn.ExceedingData
658 .. autoclass:: pyderasn.LenIndefForm
659 .. autoclass:: pyderasn.TagMismatch
660 .. autoclass:: pyderasn.InvalidLength
661 .. autoclass:: pyderasn.InvalidOID
662 .. autoclass:: pyderasn.ObjUnknown
663 .. autoclass:: pyderasn.ObjNotReady
664 .. autoclass:: pyderasn.InvalidValueType
665 .. autoclass:: pyderasn.BoundsError
672 You can decode DER/BER files using command line abilities::
674 $ python -m pyderasn --schema tests.test_crts:Certificate path/to/file
676 If there is no schema for your file, then you can try parsing it without,
677 but of course IMPLICIT tags will often make it impossible. But result is
678 good enough for the certificate above::
680 $ python -m pyderasn path/to/file
681 0 [1,3,1604] . >: SEQUENCE OF
682 4 [1,3,1453] . . >: SEQUENCE OF
683 8 [0,0, 5] . . . . >: [0] ANY
684 . . . . . A0:03:02:01:02
685 13 [1,1, 3] . . . . >: INTEGER 61595
686 18 [1,1, 13] . . . . >: SEQUENCE OF
687 20 [1,1, 9] . . . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
688 31 [1,1, 0] . . . . . . >: NULL
689 33 [1,3, 274] . . . . >: SEQUENCE OF
690 37 [1,1, 11] . . . . . . >: SET OF
691 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
692 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER 2.5.4.6
693 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
695 1409 [1,1, 50] . . . . . . >: SEQUENCE OF
696 1411 [1,1, 8] . . . . . . . . >: OBJECT IDENTIFIER 1.3.6.1.5.5.7.1.1
697 1421 [1,1, 38] . . . . . . . . >: OCTET STRING 38 bytes
698 . . . . . . . . . 30:24:30:22:06:08:2B:06:01:05:05:07:30:01:86:16
699 . . . . . . . . . 68:74:74:70:3A:2F:2F:6F:63:73:70:2E:69:70:73:63
700 . . . . . . . . . 61:2E:63:6F:6D:2F
701 1461 [1,1, 13] . . >: SEQUENCE OF
702 1463 [1,1, 9] . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
703 1474 [1,1, 0] . . . . >: NULL
704 1476 [1,2, 129] . . >: BIT STRING 1024 bits
705 . . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
706 . . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
712 If you have got dictionaries with ObjectIdentifiers, like example one
713 from ``tests/test_crts.py``::
716 "1.2.840.113549.1.1.1": "id-rsaEncryption",
717 "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
719 "2.5.4.10": "id-at-organizationName",
720 "2.5.4.11": "id-at-organizationalUnitName",
723 then you can pass it to pretty printer to see human readable OIDs::
725 $ python -m pyderasn --oids tests.test_crts:stroid2name path/to/file
727 37 [1,1, 11] . . . . . . >: SET OF
728 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
729 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
730 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
731 50 [1,1, 18] . . . . . . >: SET OF
732 52 [1,1, 16] . . . . . . . . >: SEQUENCE OF
733 54 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
734 59 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
735 70 [1,1, 18] . . . . . . >: SET OF
736 72 [1,1, 16] . . . . . . . . >: SEQUENCE OF
737 74 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
738 79 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
744 Each decoded element has so-called decode path: sequence of structure
745 names it is passing during the decode process. Each element has its own
746 unique path inside the whole ASN.1 tree. You can print it out with
747 ``--print-decode-path`` option::
749 $ python -m pyderasn --schema path.to:Certificate --print-decode-path path/to/file
750 0 [1,3,1604] Certificate SEQUENCE []
751 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE [tbsCertificate]
752 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL [tbsCertificate:version]
753 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595 [tbsCertificate:serialNumber]
754 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE [tbsCertificate:signature]
755 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5 [tbsCertificate:signature:algorithm]
756 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL [tbsCertificate:signature:parameters]
758 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence [tbsCertificate:issuer]
759 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF [tbsCertificate:issuer:rdnSequence]
760 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF [tbsCertificate:issuer:rdnSequence:0]
761 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE [tbsCertificate:issuer:rdnSequence:0:0]
762 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6 [tbsCertificate:issuer:rdnSequence:0:0:type]
763 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY [tbsCertificate:issuer:rdnSequence:0:0:value]
764 . . . . . . . 13:02:45:53
765 46 [1,1, 2] . . . . . . . DEFINED BY 2.5.4.6: CountryName PrintableString ES [tbsCertificate:issuer:rdnSequence:0:0:value:DEFINED BY 2.5.4.6]
768 Now you can print only the specified tree, for example signature algorithm::
770 $ python -m pyderasn --schema path.to:Certificate --decode-path-only tbsCertificate:signature path/to/file
771 18 [1,1, 13] AlgorithmIdentifier SEQUENCE
772 20 [1,1, 9] . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
773 31 [0,0, 2] . parameters: [UNIV 5] ANY OPTIONAL
777 from codecs import getdecoder
778 from codecs import getencoder
779 from collections import namedtuple
780 from collections import OrderedDict
781 from copy import copy
782 from datetime import datetime
783 from datetime import timedelta
784 from io import BytesIO
785 from math import ceil
786 from mmap import mmap
787 from mmap import PROT_READ
788 from operator import attrgetter
789 from string import ascii_letters
790 from string import digits
791 from sys import version_info
792 from unicodedata import category as unicat
794 from six import add_metaclass
795 from six import binary_type
796 from six import byte2int
797 from six import indexbytes
798 from six import int2byte
799 from six import integer_types
800 from six import iterbytes
801 from six import iteritems
802 from six import itervalues
804 from six import string_types
805 from six import text_type
806 from six import unichr as six_unichr
807 from six.moves import xrange as six_xrange
811 from termcolor import colored
812 except ImportError: # pragma: no cover
813 def colored(what, *args, **kwargs):
861 "TagClassApplication",
865 "TagFormConstructed",
876 TagClassUniversal = 0
877 TagClassApplication = 1 << 6
878 TagClassContext = 1 << 7
879 TagClassPrivate = 1 << 6 | 1 << 7
881 TagFormConstructed = 1 << 5
884 TagClassApplication: "APPLICATION ",
885 TagClassPrivate: "PRIVATE ",
886 TagClassUniversal: "UNIV ",
890 LENINDEF = b"\x80" # length indefinite mark
891 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
892 NAMEDTUPLE_KWARGS = {} if version_info < (3, 6) else {"module": __name__}
893 SET01 = frozenset("01")
894 DECIMALS = frozenset(digits)
899 """Make mmap-ed memoryview for reading from file
901 :param fd: file object
902 :returns: memoryview over read-only mmap-ing of the whole file
904 return memoryview(mmap(fd.fileno(), 0, prot=PROT_READ))
907 if not set(value) <= DECIMALS:
908 raise ValueError("non-pure integer")
911 def fractions2float(fractions_raw):
912 pureint(fractions_raw)
913 return float("0." + fractions_raw)
916 def get_def_by_path(defines_by_path, sub_decode_path):
917 """Get define by decode path
919 for path, define in defines_by_path:
920 if len(path) != len(sub_decode_path):
922 for p1, p2 in zip(path, sub_decode_path):
923 if (not p1 is any) and (p1 != p2):
929 ########################################################################
931 ########################################################################
933 class ASN1Error(ValueError):
937 class DecodeError(ASN1Error):
938 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
940 :param str msg: reason of decode failing
941 :param klass: optional exact DecodeError inherited class (like
942 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
943 :py:exc:`InvalidLength`)
944 :param decode_path: tuple of strings. It contains human
945 readable names of the fields through which
946 decoding process has passed
947 :param int offset: binary offset where failure happened
949 super(DecodeError, self).__init__()
952 self.decode_path = decode_path
958 "" if self.klass is None else self.klass.__name__,
960 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
961 if len(self.decode_path) > 0 else ""
963 ("(at %d)" % self.offset) if self.offset > 0 else "",
969 return "%s(%s)" % (self.__class__.__name__, self)
972 class NotEnoughData(DecodeError):
976 class ExceedingData(ASN1Error):
977 def __init__(self, nbytes):
978 super(ExceedingData, self).__init__()
982 return "%d trailing bytes" % self.nbytes
985 return "%s(%s)" % (self.__class__.__name__, self)
988 class LenIndefForm(DecodeError):
992 class TagMismatch(DecodeError):
996 class InvalidLength(DecodeError):
1000 class InvalidOID(DecodeError):
1004 class ObjUnknown(ASN1Error):
1005 def __init__(self, name):
1006 super(ObjUnknown, self).__init__()
1010 return "object is unknown: %s" % self.name
1013 return "%s(%s)" % (self.__class__.__name__, self)
1016 class ObjNotReady(ASN1Error):
1017 def __init__(self, name):
1018 super(ObjNotReady, self).__init__()
1022 return "object is not ready: %s" % self.name
1025 return "%s(%s)" % (self.__class__.__name__, self)
1028 class InvalidValueType(ASN1Error):
1029 def __init__(self, expected_types):
1030 super(InvalidValueType, self).__init__()
1031 self.expected_types = expected_types
1034 return "invalid value type, expected: %s" % ", ".join(
1035 [repr(t) for t in self.expected_types]
1039 return "%s(%s)" % (self.__class__.__name__, self)
1042 class BoundsError(ASN1Error):
1043 def __init__(self, bound_min, value, bound_max):
1044 super(BoundsError, self).__init__()
1045 self.bound_min = bound_min
1047 self.bound_max = bound_max
1050 return "unsatisfied bounds: %s <= %s <= %s" % (
1057 return "%s(%s)" % (self.__class__.__name__, self)
1060 ########################################################################
1062 ########################################################################
1064 _hexdecoder = getdecoder("hex")
1065 _hexencoder = getencoder("hex")
1069 """Binary data to hexadecimal string convert
1071 return _hexdecoder(data)[0]
1075 """Hexadecimal string to binary data convert
1077 return _hexencoder(data)[0].decode("ascii")
1080 def int_bytes_len(num, byte_len=8):
1083 return int(ceil(float(num.bit_length()) / byte_len))
1086 def zero_ended_encode(num):
1087 octets = bytearray(int_bytes_len(num, 7))
1089 octets[i] = num & 0x7F
1093 octets[i] = 0x80 | (num & 0x7F)
1096 return bytes(octets)
1099 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
1100 """Encode tag to binary form
1102 :param int num: tag's number
1103 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
1104 :py:data:`pyderasn.TagClassContext`,
1105 :py:data:`pyderasn.TagClassApplication`,
1106 :py:data:`pyderasn.TagClassPrivate`)
1107 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
1108 :py:data:`pyderasn.TagFormConstructed`)
1112 return int2byte(klass | form | num)
1113 # [XX|X|11111][1.......][1.......] ... [0.......]
1114 return int2byte(klass | form | 31) + zero_ended_encode(num)
1117 def tag_decode(tag):
1118 """Decode tag from binary form
1122 No validation is performed, assuming that it has already passed.
1124 It returns tuple with three integers, as
1125 :py:func:`pyderasn.tag_encode` accepts.
1127 first_octet = byte2int(tag)
1128 klass = first_octet & 0xC0
1129 form = first_octet & 0x20
1130 if first_octet & 0x1F < 0x1F:
1131 return (klass, form, first_octet & 0x1F)
1133 for octet in iterbytes(tag[1:]):
1136 return (klass, form, num)
1140 """Create CONTEXT PRIMITIVE tag
1142 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
1146 """Create CONTEXT CONSTRUCTED tag
1148 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
1151 def tag_strip(data):
1152 """Take off tag from the data
1154 :returns: (encoded tag, tag length, remaining data)
1157 raise NotEnoughData("no data at all")
1158 if byte2int(data) & 0x1F < 31:
1159 return data[:1], 1, data[1:]
1164 raise DecodeError("unfinished tag")
1165 if indexbytes(data, i) & 0x80 == 0:
1168 return data[:i], i, data[i:]
1174 octets = bytearray(int_bytes_len(l) + 1)
1175 octets[0] = 0x80 | (len(octets) - 1)
1176 for i in six_xrange(len(octets) - 1, 0, -1):
1177 octets[i] = l & 0xFF
1179 return bytes(octets)
1182 def len_decode(data):
1185 :returns: (decoded length, length's length, remaining data)
1186 :raises LenIndefForm: if indefinite form encoding is met
1189 raise NotEnoughData("no data at all")
1190 first_octet = byte2int(data)
1191 if first_octet & 0x80 == 0:
1192 return first_octet, 1, data[1:]
1193 octets_num = first_octet & 0x7F
1194 if octets_num + 1 > len(data):
1195 raise NotEnoughData("encoded length is longer than data")
1197 raise LenIndefForm()
1198 if byte2int(data[1:]) == 0:
1199 raise DecodeError("leading zeros")
1201 for v in iterbytes(data[1:1 + octets_num]):
1204 raise DecodeError("long form instead of short one")
1205 return l, 1 + octets_num, data[1 + octets_num:]
1208 LEN1K = len_encode(1000)
1211 def write_full(writer, data):
1212 """Fully write provided data
1214 BytesIO does not guarantee that the whole data will be written at once.
1216 data = memoryview(data)
1218 while written != len(data):
1219 n = writer(data[written:])
1221 raise ValueError("can not write to buf")
1225 ########################################################################
1227 ########################################################################
1229 class AutoAddSlots(type):
1230 def __new__(cls, name, bases, _dict):
1231 _dict["__slots__"] = _dict.get("__slots__", ())
1232 return type.__new__(cls, name, bases, _dict)
1235 BasicState = namedtuple("BasicState", (
1248 ), **NAMEDTUPLE_KWARGS)
1251 @add_metaclass(AutoAddSlots)
1253 """Common ASN.1 object class
1255 All ASN.1 types are inherited from it. It has metaclass that
1256 automatically adds ``__slots__`` to all inherited classes.
1281 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1282 self._expl = getattr(self, "expl", None) if expl is None else expl
1283 if self.tag != self.tag_default and self._expl is not None:
1284 raise ValueError("implicit and explicit tags can not be set simultaneously")
1285 if self.tag is None:
1286 self._tag_order = None
1288 tag_class, _, tag_num = tag_decode(
1289 self.tag if self._expl is None else self._expl
1291 self._tag_order = (tag_class, tag_num)
1292 if default is not None:
1294 self.optional = optional
1295 self.offset, self.llen, self.vlen = _decoded
1297 self.expl_lenindef = False
1298 self.lenindef = False
1299 self.ber_encoded = False
1302 def ready(self): # pragma: no cover
1303 """Is object ready to be encoded?
1305 raise NotImplementedError()
1307 def _assert_ready(self):
1309 raise ObjNotReady(self.__class__.__name__)
1313 """Is either object or any elements inside is BER encoded?
1315 return self.expl_lenindef or self.lenindef or self.ber_encoded
1319 """Is object decoded?
1321 return (self.llen + self.vlen) > 0
1323 def __getstate__(self): # pragma: no cover
1324 """Used for making safe to be mutable pickleable copies
1326 raise NotImplementedError()
1328 def __setstate__(self, state):
1329 if state.version != __version__:
1330 raise ValueError("data is pickled by different PyDERASN version")
1331 self.tag = state.tag
1332 self._tag_order = state.tag_order
1333 self._expl = state.expl
1334 self.default = state.default
1335 self.optional = state.optional
1336 self.offset = state.offset
1337 self.llen = state.llen
1338 self.vlen = state.vlen
1339 self.expl_lenindef = state.expl_lenindef
1340 self.lenindef = state.lenindef
1341 self.ber_encoded = state.ber_encoded
1344 def tag_order(self):
1345 """Tag's (class, number) used for DER/CER sorting
1347 return self._tag_order
1350 def tag_order_cer(self):
1351 return self.tag_order
1355 """See :ref:`decoding`
1357 return len(self.tag)
1361 """See :ref:`decoding`
1363 return self.tlen + self.llen + self.vlen
1365 def __str__(self): # pragma: no cover
1366 return self.__bytes__() if PY2 else self.__unicode__()
1368 def __ne__(self, their):
1369 return not(self == their)
1371 def __gt__(self, their): # pragma: no cover
1372 return not(self < their)
1374 def __le__(self, their): # pragma: no cover
1375 return (self == their) or (self < their)
1377 def __ge__(self, their): # pragma: no cover
1378 return (self == their) or (self > their)
1380 def _encode(self): # pragma: no cover
1381 raise NotImplementedError()
1383 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode): # pragma: no cover
1384 yield NotImplemented
1387 """Encode the structure
1389 :returns: DER representation
1391 raw = self._encode()
1392 if self._expl is None:
1394 return b"".join((self._expl, len_encode(len(raw)), raw))
1396 def encode_cer(self, writer):
1397 if self._expl is not None:
1398 write_full(writer, self._expl + LENINDEF)
1399 if getattr(self, "der_forced", False):
1400 write_full(writer, self._encode())
1402 self._encode_cer(writer)
1403 if self._expl is not None:
1404 write_full(writer, EOC)
1406 def _encode_cer(self, writer):
1407 write_full(writer, self._encode())
1409 def hexencode(self):
1410 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1412 return hexenc(self.encode())
1422 _ctx_immutable=True,
1424 result = next(self.decode_evgen(
1436 _, obj, tail = result
1447 _ctx_immutable=True,
1452 :param data: either binary or memoryview
1453 :param int offset: initial data's offset
1454 :param bool leavemm: do we need to leave memoryview of remaining
1455 data as is, or convert it to bytes otherwise
1456 :param ctx: optional :ref:`context <ctx>` governing decoding process
1457 :param tag_only: decode only the tag, without length and contents
1458 (used only in Choice and Set structures, trying to
1459 determine if tag satisfies the schema)
1460 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1462 :returns: (Obj, remaining data)
1464 .. seealso:: :ref:`decoding`
1468 elif _ctx_immutable:
1470 tlv = memoryview(data)
1473 get_def_by_path(ctx.get("evgen_mode_upto", ()), decode_path) is not None
1476 if self._expl is None:
1477 for result in self._decode(
1480 decode_path=decode_path,
1483 evgen_mode=_evgen_mode,
1488 _decode_path, obj, tail = result
1489 if not _decode_path is decode_path:
1493 t, tlen, lv = tag_strip(tlv)
1494 except DecodeError as err:
1495 raise err.__class__(
1497 klass=self.__class__,
1498 decode_path=decode_path,
1503 klass=self.__class__,
1504 decode_path=decode_path,
1508 l, llen, v = len_decode(lv)
1509 except LenIndefForm as err:
1510 if not ctx.get("bered", False):
1511 raise err.__class__(
1513 klass=self.__class__,
1514 decode_path=decode_path,
1518 offset += tlen + llen
1519 for result in self._decode(
1522 decode_path=decode_path,
1525 evgen_mode=_evgen_mode,
1527 if tag_only: # pragma: no cover
1530 _decode_path, obj, tail = result
1531 if not _decode_path is decode_path:
1533 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1534 if eoc_expected.tobytes() != EOC:
1537 klass=self.__class__,
1538 decode_path=decode_path,
1542 obj.expl_lenindef = True
1543 except DecodeError as err:
1544 raise err.__class__(
1546 klass=self.__class__,
1547 decode_path=decode_path,
1552 raise NotEnoughData(
1553 "encoded length is longer than data",
1554 klass=self.__class__,
1555 decode_path=decode_path,
1558 for result in self._decode(
1560 offset=offset + tlen + llen,
1561 decode_path=decode_path,
1564 evgen_mode=_evgen_mode,
1566 if tag_only: # pragma: no cover
1569 _decode_path, obj, tail = result
1570 if not _decode_path is decode_path:
1572 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1574 "explicit tag out-of-bound, longer than data",
1575 klass=self.__class__,
1576 decode_path=decode_path,
1579 yield decode_path, obj, (tail if leavemm else tail.tobytes())
1581 def decod(self, data, offset=0, decode_path=(), ctx=None):
1582 """Decode the data, check that tail is empty
1584 :raises ExceedingData: if tail is not empty
1586 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1587 (decode without tail) that also checks that there is no
1590 obj, tail = self.decode(
1593 decode_path=decode_path,
1598 raise ExceedingData(len(tail))
1601 def hexdecode(self, data, *args, **kwargs):
1602 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1604 return self.decode(hexdec(data), *args, **kwargs)
1606 def hexdecod(self, data, *args, **kwargs):
1607 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1609 return self.decod(hexdec(data), *args, **kwargs)
1613 """See :ref:`decoding`
1615 return self._expl is not None
1619 """See :ref:`decoding`
1624 def expl_tlen(self):
1625 """See :ref:`decoding`
1627 return len(self._expl)
1630 def expl_llen(self):
1631 """See :ref:`decoding`
1633 if self.expl_lenindef:
1635 return len(len_encode(self.tlvlen))
1638 def expl_offset(self):
1639 """See :ref:`decoding`
1641 return self.offset - self.expl_tlen - self.expl_llen
1644 def expl_vlen(self):
1645 """See :ref:`decoding`
1650 def expl_tlvlen(self):
1651 """See :ref:`decoding`
1653 return self.expl_tlen + self.expl_llen + self.expl_vlen
1656 def fulloffset(self):
1657 """See :ref:`decoding`
1659 return self.expl_offset if self.expled else self.offset
1663 """See :ref:`decoding`
1665 return self.expl_tlvlen if self.expled else self.tlvlen
1667 def pps_lenindef(self, decode_path):
1668 if self.lenindef and not (
1669 getattr(self, "defined", None) is not None and
1670 self.defined[1].lenindef
1673 asn1_type_name="EOC",
1675 decode_path=decode_path,
1677 self.offset + self.tlvlen -
1678 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1686 if self.expl_lenindef:
1688 asn1_type_name="EOC",
1689 obj_name="EXPLICIT",
1690 decode_path=decode_path,
1691 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1700 def encode_cer(obj):
1701 """Encode to CER in memory
1704 obj.encode_cer(buf.write)
1705 return buf.getvalue()
1708 class DecodePathDefBy(object):
1709 """DEFINED BY representation inside decode path
1711 __slots__ = ("defined_by",)
1713 def __init__(self, defined_by):
1714 self.defined_by = defined_by
1716 def __ne__(self, their):
1717 return not(self == their)
1719 def __eq__(self, their):
1720 if not isinstance(their, self.__class__):
1722 return self.defined_by == their.defined_by
1725 return "DEFINED BY " + str(self.defined_by)
1728 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1731 ########################################################################
1733 ########################################################################
1735 PP = namedtuple("PP", (
1758 ), **NAMEDTUPLE_KWARGS)
1763 asn1_type_name="unknown",
1780 expl_lenindef=False,
1811 def _colourize(what, colour, with_colours, attrs=("bold",)):
1812 return colored(what, colour, attrs=attrs) if with_colours else what
1815 def colonize_hex(hexed):
1816 """Separate hexadecimal string with colons
1818 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1827 with_decode_path=False,
1828 decode_path_len_decrease=0,
1835 " " if pp.expl_offset is None else
1836 ("-%d" % (pp.offset - pp.expl_offset))
1838 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1840 col = _colourize(col, "red", with_colours, ())
1841 col += _colourize("B", "red", with_colours) if pp.bered else " "
1843 col = "[%d,%d,%4d]%s" % (
1847 LENINDEF_PP_CHAR if pp.lenindef else " "
1849 col = _colourize(col, "green", with_colours, ())
1851 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1852 if decode_path_len > 0:
1853 cols.append(" ." * decode_path_len)
1854 ent = pp.decode_path[-1]
1855 if isinstance(ent, DecodePathDefBy):
1856 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1857 value = str(ent.defined_by)
1860 len(oid_maps) > 0 and
1861 ent.defined_by.asn1_type_name ==
1862 ObjectIdentifier.asn1_type_name
1864 for oid_map in oid_maps:
1865 oid_name = oid_map.get(value)
1866 if oid_name is not None:
1867 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1869 if oid_name is None:
1870 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1872 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1873 if pp.expl is not None:
1874 klass, _, num = pp.expl
1875 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1876 cols.append(_colourize(col, "blue", with_colours))
1877 if pp.impl is not None:
1878 klass, _, num = pp.impl
1879 col = "[%s%d]" % (TagClassReprs[klass], num)
1880 cols.append(_colourize(col, "blue", with_colours))
1881 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1882 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1884 cols.append(_colourize("BER", "red", with_colours))
1885 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1886 if pp.value is not None:
1888 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1890 len(oid_maps) > 0 and
1891 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1893 for oid_map in oid_maps:
1894 oid_name = oid_map.get(value)
1895 if oid_name is not None:
1896 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1898 if pp.asn1_type_name == Integer.asn1_type_name:
1899 hex_repr = hex(int(pp.obj._value))[2:].upper()
1900 if len(hex_repr) % 2 != 0:
1901 hex_repr = "0" + hex_repr
1902 cols.append(_colourize(
1903 "(%s)" % colonize_hex(hex_repr),
1908 if pp.blob.__class__ == binary_type:
1909 cols.append(hexenc(pp.blob))
1910 elif pp.blob.__class__ == tuple:
1911 cols.append(", ".join(pp.blob))
1913 cols.append(_colourize("OPTIONAL", "red", with_colours))
1915 cols.append(_colourize("DEFAULT", "red", with_colours))
1916 if with_decode_path:
1917 cols.append(_colourize(
1918 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1922 return " ".join(cols)
1925 def pp_console_blob(pp, decode_path_len_decrease=0):
1926 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1927 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1928 if decode_path_len > 0:
1929 cols.append(" ." * (decode_path_len + 1))
1930 if pp.blob.__class__ == binary_type:
1931 blob = hexenc(pp.blob).upper()
1932 for i in six_xrange(0, len(blob), 32):
1933 chunk = blob[i:i + 32]
1934 yield " ".join(cols + [colonize_hex(chunk)])
1935 elif pp.blob.__class__ == tuple:
1936 yield " ".join(cols + [", ".join(pp.blob)])
1944 with_decode_path=False,
1945 decode_path_only=(),
1948 """Pretty print object
1950 :param Obj obj: object you want to pretty print
1951 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1952 Its human readable form is printed when OID is met
1953 :param big_blobs: if large binary objects are met (like OctetString
1954 values), do we need to print them too, on separate
1956 :param with_colours: colourize output, if ``termcolor`` library
1958 :param with_decode_path: print decode path
1959 :param decode_path_only: print only that specified decode path
1961 def _pprint_pps(pps):
1963 if hasattr(pp, "_fields"):
1965 decode_path_only != () and
1967 str(p) for p in pp.decode_path[:len(decode_path_only)]
1968 ) != decode_path_only
1972 yield pp_console_row(
1977 with_colours=with_colours,
1978 with_decode_path=with_decode_path,
1979 decode_path_len_decrease=len(decode_path_only),
1981 for row in pp_console_blob(
1983 decode_path_len_decrease=len(decode_path_only),
1987 yield pp_console_row(
1992 with_colours=with_colours,
1993 with_decode_path=with_decode_path,
1994 decode_path_len_decrease=len(decode_path_only),
1997 for row in _pprint_pps(pp):
1999 return "\n".join(_pprint_pps(obj.pps(decode_path)))
2002 ########################################################################
2003 # ASN.1 primitive types
2004 ########################################################################
2006 BooleanState = namedtuple(
2008 BasicState._fields + ("value",),
2014 """``BOOLEAN`` boolean type
2016 >>> b = Boolean(True)
2018 >>> b == Boolean(True)
2024 tag_default = tag_encode(1)
2025 asn1_type_name = "BOOLEAN"
2037 :param value: set the value. Either boolean type, or
2038 :py:class:`pyderasn.Boolean` object
2039 :param bytes impl: override default tag with ``IMPLICIT`` one
2040 :param bytes expl: override default tag with ``EXPLICIT`` one
2041 :param default: set default value. Type same as in ``value``
2042 :param bool optional: is object ``OPTIONAL`` in sequence
2044 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
2045 self._value = None if value is None else self._value_sanitize(value)
2046 if default is not None:
2047 default = self._value_sanitize(default)
2048 self.default = self.__class__(
2054 self._value = default
2056 def _value_sanitize(self, value):
2057 if value.__class__ == bool:
2059 if issubclass(value.__class__, Boolean):
2061 raise InvalidValueType((self.__class__, bool))
2065 return self._value is not None
2067 def __getstate__(self):
2068 return BooleanState(
2084 def __setstate__(self, state):
2085 super(Boolean, self).__setstate__(state)
2086 self._value = state.value
2088 def __nonzero__(self):
2089 self._assert_ready()
2093 self._assert_ready()
2096 def __eq__(self, their):
2097 if their.__class__ == bool:
2098 return self._value == their
2099 if not issubclass(their.__class__, Boolean):
2102 self._value == their._value and
2103 self.tag == their.tag and
2104 self._expl == their._expl
2115 return self.__class__(
2117 impl=self.tag if impl is None else impl,
2118 expl=self._expl if expl is None else expl,
2119 default=self.default if default is None else default,
2120 optional=self.optional if optional is None else optional,
2124 self._assert_ready()
2128 (b"\xFF" if self._value else b"\x00"),
2131 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2133 t, _, lv = tag_strip(tlv)
2134 except DecodeError as err:
2135 raise err.__class__(
2137 klass=self.__class__,
2138 decode_path=decode_path,
2143 klass=self.__class__,
2144 decode_path=decode_path,
2151 l, _, v = len_decode(lv)
2152 except DecodeError as err:
2153 raise err.__class__(
2155 klass=self.__class__,
2156 decode_path=decode_path,
2160 raise InvalidLength(
2161 "Boolean's length must be equal to 1",
2162 klass=self.__class__,
2163 decode_path=decode_path,
2167 raise NotEnoughData(
2168 "encoded length is longer than data",
2169 klass=self.__class__,
2170 decode_path=decode_path,
2173 first_octet = byte2int(v)
2175 if first_octet == 0:
2177 elif first_octet == 0xFF:
2179 elif ctx.get("bered", False):
2184 "unacceptable Boolean value",
2185 klass=self.__class__,
2186 decode_path=decode_path,
2189 obj = self.__class__(
2193 default=self.default,
2194 optional=self.optional,
2195 _decoded=(offset, 1, 1),
2197 obj.ber_encoded = ber_encoded
2198 yield decode_path, obj, v[1:]
2201 return pp_console_row(next(self.pps()))
2203 def pps(self, decode_path=()):
2206 asn1_type_name=self.asn1_type_name,
2207 obj_name=self.__class__.__name__,
2208 decode_path=decode_path,
2209 value=str(self._value) if self.ready else None,
2210 optional=self.optional,
2211 default=self == self.default,
2212 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2213 expl=None if self._expl is None else tag_decode(self._expl),
2218 expl_offset=self.expl_offset if self.expled else None,
2219 expl_tlen=self.expl_tlen if self.expled else None,
2220 expl_llen=self.expl_llen if self.expled else None,
2221 expl_vlen=self.expl_vlen if self.expled else None,
2222 expl_lenindef=self.expl_lenindef,
2223 ber_encoded=self.ber_encoded,
2226 for pp in self.pps_lenindef(decode_path):
2230 IntegerState = namedtuple(
2232 BasicState._fields + ("specs", "value", "bound_min", "bound_max"),
2238 """``INTEGER`` integer type
2240 >>> b = Integer(-123)
2242 >>> b == Integer(-123)
2247 >>> Integer(2, bounds=(1, 3))
2249 >>> Integer(5, bounds=(1, 3))
2250 Traceback (most recent call last):
2251 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2255 class Version(Integer):
2262 >>> v = Version("v1")
2269 {'v3': 2, 'v1': 0, 'v2': 1}
2271 __slots__ = ("specs", "_bound_min", "_bound_max")
2272 tag_default = tag_encode(2)
2273 asn1_type_name = "INTEGER"
2287 :param value: set the value. Either integer type, named value
2288 (if ``schema`` is specified in the class), or
2289 :py:class:`pyderasn.Integer` object
2290 :param bounds: set ``(MIN, MAX)`` value constraint.
2291 (-inf, +inf) by default
2292 :param bytes impl: override default tag with ``IMPLICIT`` one
2293 :param bytes expl: override default tag with ``EXPLICIT`` one
2294 :param default: set default value. Type same as in ``value``
2295 :param bool optional: is object ``OPTIONAL`` in sequence
2297 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2299 specs = getattr(self, "schema", {}) if _specs is None else _specs
2300 self.specs = specs if specs.__class__ == dict else dict(specs)
2301 self._bound_min, self._bound_max = getattr(
2304 (float("-inf"), float("+inf")),
2305 ) if bounds is None else bounds
2306 if value is not None:
2307 self._value = self._value_sanitize(value)
2308 if default is not None:
2309 default = self._value_sanitize(default)
2310 self.default = self.__class__(
2316 if self._value is None:
2317 self._value = default
2319 def _value_sanitize(self, value):
2320 if isinstance(value, integer_types):
2322 elif issubclass(value.__class__, Integer):
2323 value = value._value
2324 elif value.__class__ == str:
2325 value = self.specs.get(value)
2327 raise ObjUnknown("integer value: %s" % value)
2329 raise InvalidValueType((self.__class__, int, str))
2330 if not self._bound_min <= value <= self._bound_max:
2331 raise BoundsError(self._bound_min, value, self._bound_max)
2336 return self._value is not None
2338 def __getstate__(self):
2339 return IntegerState(
2358 def __setstate__(self, state):
2359 super(Integer, self).__setstate__(state)
2360 self.specs = state.specs
2361 self._value = state.value
2362 self._bound_min = state.bound_min
2363 self._bound_max = state.bound_max
2366 self._assert_ready()
2367 return int(self._value)
2370 self._assert_ready()
2373 bytes(self._expl or b"") +
2374 str(self._value).encode("ascii"),
2377 def __eq__(self, their):
2378 if isinstance(their, integer_types):
2379 return self._value == their
2380 if not issubclass(their.__class__, Integer):
2383 self._value == their._value and
2384 self.tag == their.tag and
2385 self._expl == their._expl
2388 def __lt__(self, their):
2389 return self._value < their._value
2393 """Return named representation (if exists) of the value
2395 for name, value in iteritems(self.specs):
2396 if value == self._value:
2409 return self.__class__(
2412 (self._bound_min, self._bound_max)
2413 if bounds is None else bounds
2415 impl=self.tag if impl is None else impl,
2416 expl=self._expl if expl is None else expl,
2417 default=self.default if default is None else default,
2418 optional=self.optional if optional is None else optional,
2423 self._assert_ready()
2427 octets = bytearray([0])
2431 octets = bytearray()
2433 octets.append((value & 0xFF) ^ 0xFF)
2435 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2438 octets = bytearray()
2440 octets.append(value & 0xFF)
2442 if octets[-1] & 0x80 > 0:
2445 octets = bytes(octets)
2447 bytes_len = ceil(value.bit_length() / 8) or 1
2450 octets = value.to_bytes(
2455 except OverflowError:
2459 return b"".join((self.tag, len_encode(len(octets)), octets))
2461 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2463 t, _, lv = tag_strip(tlv)
2464 except DecodeError as err:
2465 raise err.__class__(
2467 klass=self.__class__,
2468 decode_path=decode_path,
2473 klass=self.__class__,
2474 decode_path=decode_path,
2481 l, llen, v = len_decode(lv)
2482 except DecodeError as err:
2483 raise err.__class__(
2485 klass=self.__class__,
2486 decode_path=decode_path,
2490 raise NotEnoughData(
2491 "encoded length is longer than data",
2492 klass=self.__class__,
2493 decode_path=decode_path,
2497 raise NotEnoughData(
2499 klass=self.__class__,
2500 decode_path=decode_path,
2503 v, tail = v[:l], v[l:]
2504 first_octet = byte2int(v)
2506 second_octet = byte2int(v[1:])
2508 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2509 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2512 "non normalized integer",
2513 klass=self.__class__,
2514 decode_path=decode_path,
2519 if first_octet & 0x80 > 0:
2520 octets = bytearray()
2521 for octet in bytearray(v):
2522 octets.append(octet ^ 0xFF)
2523 for octet in octets:
2524 value = (value << 8) | octet
2528 for octet in bytearray(v):
2529 value = (value << 8) | octet
2531 value = int.from_bytes(v, byteorder="big", signed=True)
2533 obj = self.__class__(
2535 bounds=(self._bound_min, self._bound_max),
2538 default=self.default,
2539 optional=self.optional,
2541 _decoded=(offset, llen, l),
2543 except BoundsError as err:
2546 klass=self.__class__,
2547 decode_path=decode_path,
2550 yield decode_path, obj, tail
2553 return pp_console_row(next(self.pps()))
2555 def pps(self, decode_path=()):
2558 asn1_type_name=self.asn1_type_name,
2559 obj_name=self.__class__.__name__,
2560 decode_path=decode_path,
2561 value=(self.named or str(self._value)) if self.ready else None,
2562 optional=self.optional,
2563 default=self == self.default,
2564 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2565 expl=None if self._expl is None else tag_decode(self._expl),
2570 expl_offset=self.expl_offset if self.expled else None,
2571 expl_tlen=self.expl_tlen if self.expled else None,
2572 expl_llen=self.expl_llen if self.expled else None,
2573 expl_vlen=self.expl_vlen if self.expled else None,
2574 expl_lenindef=self.expl_lenindef,
2577 for pp in self.pps_lenindef(decode_path):
2581 BitStringState = namedtuple(
2583 BasicState._fields + ("specs", "value", "tag_constructed", "defined"),
2588 class BitString(Obj):
2589 """``BIT STRING`` bit string type
2591 >>> BitString(b"hello world")
2592 BIT STRING 88 bits 68656c6c6f20776f726c64
2595 >>> b == b"hello world"
2600 >>> BitString("'0A3B5F291CD'H")
2601 BIT STRING 44 bits 0a3b5f291cd0
2602 >>> b = BitString("'010110000000'B")
2603 BIT STRING 12 bits 5800
2606 >>> b[0], b[1], b[2], b[3]
2607 (False, True, False, True)
2611 [False, True, False, True, True, False, False, False, False, False, False, False]
2615 class KeyUsage(BitString):
2617 ("digitalSignature", 0),
2618 ("nonRepudiation", 1),
2619 ("keyEncipherment", 2),
2622 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2623 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2625 ['nonRepudiation', 'keyEncipherment']
2627 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2631 Pay attention that BIT STRING can be encoded both in primitive
2632 and constructed forms. Decoder always checks constructed form tag
2633 additionally to specified primitive one. If BER decoding is
2634 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2635 of DER restrictions.
2637 __slots__ = ("tag_constructed", "specs", "defined")
2638 tag_default = tag_encode(3)
2639 asn1_type_name = "BIT STRING"
2652 :param value: set the value. Either binary type, tuple of named
2653 values (if ``schema`` is specified in the class),
2654 string in ``'XXX...'B`` form, or
2655 :py:class:`pyderasn.BitString` object
2656 :param bytes impl: override default tag with ``IMPLICIT`` one
2657 :param bytes expl: override default tag with ``EXPLICIT`` one
2658 :param default: set default value. Type same as in ``value``
2659 :param bool optional: is object ``OPTIONAL`` in sequence
2661 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2662 specs = getattr(self, "schema", {}) if _specs is None else _specs
2663 self.specs = specs if specs.__class__ == dict else dict(specs)
2664 self._value = None if value is None else self._value_sanitize(value)
2665 if default is not None:
2666 default = self._value_sanitize(default)
2667 self.default = self.__class__(
2673 self._value = default
2675 tag_klass, _, tag_num = tag_decode(self.tag)
2676 self.tag_constructed = tag_encode(
2678 form=TagFormConstructed,
2682 def _bits2octets(self, bits):
2683 if len(self.specs) > 0:
2684 bits = bits.rstrip("0")
2686 bits += "0" * ((8 - (bit_len % 8)) % 8)
2687 octets = bytearray(len(bits) // 8)
2688 for i in six_xrange(len(octets)):
2689 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2690 return bit_len, bytes(octets)
2692 def _value_sanitize(self, value):
2693 if isinstance(value, (string_types, binary_type)):
2695 isinstance(value, string_types) and
2696 value.startswith("'")
2698 if value.endswith("'B"):
2700 if not frozenset(value) <= SET01:
2701 raise ValueError("B's coding contains unacceptable chars")
2702 return self._bits2octets(value)
2703 if value.endswith("'H"):
2707 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2709 if value.__class__ == binary_type:
2710 return (len(value) * 8, value)
2711 raise InvalidValueType((self.__class__, string_types, binary_type))
2712 if value.__class__ == tuple:
2715 isinstance(value[0], integer_types) and
2716 value[1].__class__ == binary_type
2721 bit = self.specs.get(name)
2723 raise ObjUnknown("BitString value: %s" % name)
2726 return self._bits2octets("")
2727 bits = frozenset(bits)
2728 return self._bits2octets("".join(
2729 ("1" if bit in bits else "0")
2730 for bit in six_xrange(max(bits) + 1)
2732 if issubclass(value.__class__, BitString):
2734 raise InvalidValueType((self.__class__, binary_type, string_types))
2738 return self._value is not None
2740 def __getstate__(self):
2741 return BitStringState(
2756 self.tag_constructed,
2760 def __setstate__(self, state):
2761 super(BitString, self).__setstate__(state)
2762 self.specs = state.specs
2763 self._value = state.value
2764 self.tag_constructed = state.tag_constructed
2765 self.defined = state.defined
2768 self._assert_ready()
2769 for i in six_xrange(self._value[0]):
2774 """Returns number of bits in the string
2776 self._assert_ready()
2777 return self._value[0]
2779 def __bytes__(self):
2780 self._assert_ready()
2781 return self._value[1]
2783 def __eq__(self, their):
2784 if their.__class__ == bytes:
2785 return self._value[1] == their
2786 if not issubclass(their.__class__, BitString):
2789 self._value == their._value and
2790 self.tag == their.tag and
2791 self._expl == their._expl
2796 """Named representation (if exists) of the bits
2798 :returns: [str(name), ...]
2800 return [name for name, bit in iteritems(self.specs) if self[bit]]
2810 return self.__class__(
2812 impl=self.tag if impl is None else impl,
2813 expl=self._expl if expl is None else expl,
2814 default=self.default if default is None else default,
2815 optional=self.optional if optional is None else optional,
2819 def __getitem__(self, key):
2820 if key.__class__ == int:
2821 bit_len, octets = self._value
2825 byte2int(memoryview(octets)[key // 8:]) >>
2828 if isinstance(key, string_types):
2829 value = self.specs.get(key)
2831 raise ObjUnknown("BitString value: %s" % key)
2833 raise InvalidValueType((int, str))
2836 self._assert_ready()
2837 bit_len, octets = self._value
2840 len_encode(len(octets) + 1),
2841 int2byte((8 - bit_len % 8) % 8),
2845 def _encode_cer(self, writer):
2846 bit_len, octets = self._value
2847 if len(octets) + 1 <= 1000:
2848 write_full(writer, self._encode())
2850 write_full(writer, self.tag_constructed)
2851 write_full(writer, LENINDEF)
2852 for offset in six_xrange(0, (len(octets) // 999) * 999, 999):
2853 write_full(writer, b"".join((
2854 BitString.tag_default,
2857 octets[offset:offset + 999],
2859 tail = octets[offset+999:]
2861 tail = int2byte((8 - bit_len % 8) % 8) + tail
2862 write_full(writer, b"".join((
2863 BitString.tag_default,
2864 len_encode(len(tail)),
2867 write_full(writer, EOC)
2869 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2871 t, tlen, lv = tag_strip(tlv)
2872 except DecodeError as err:
2873 raise err.__class__(
2875 klass=self.__class__,
2876 decode_path=decode_path,
2880 if tag_only: # pragma: no cover
2884 l, llen, v = len_decode(lv)
2885 except DecodeError as err:
2886 raise err.__class__(
2888 klass=self.__class__,
2889 decode_path=decode_path,
2893 raise NotEnoughData(
2894 "encoded length is longer than data",
2895 klass=self.__class__,
2896 decode_path=decode_path,
2900 raise NotEnoughData(
2902 klass=self.__class__,
2903 decode_path=decode_path,
2906 pad_size = byte2int(v)
2907 if l == 1 and pad_size != 0:
2909 "invalid empty value",
2910 klass=self.__class__,
2911 decode_path=decode_path,
2917 klass=self.__class__,
2918 decode_path=decode_path,
2921 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2924 klass=self.__class__,
2925 decode_path=decode_path,
2928 v, tail = v[:l], v[l:]
2929 bit_len = (len(v) - 1) * 8 - pad_size
2930 obj = self.__class__(
2931 value=None if evgen_mode else (bit_len, v[1:].tobytes()),
2934 default=self.default,
2935 optional=self.optional,
2937 _decoded=(offset, llen, l),
2940 obj._value = (bit_len, None)
2941 yield decode_path, obj, tail
2943 if t != self.tag_constructed:
2945 klass=self.__class__,
2946 decode_path=decode_path,
2949 if not ctx.get("bered", False):
2951 "unallowed BER constructed encoding",
2952 klass=self.__class__,
2953 decode_path=decode_path,
2956 if tag_only: # pragma: no cover
2961 l, llen, v = len_decode(lv)
2962 except LenIndefForm:
2963 llen, l, v = 1, 0, lv[1:]
2965 except DecodeError as err:
2966 raise err.__class__(
2968 klass=self.__class__,
2969 decode_path=decode_path,
2973 raise NotEnoughData(
2974 "encoded length is longer than data",
2975 klass=self.__class__,
2976 decode_path=decode_path,
2979 if not lenindef and l == 0:
2980 raise NotEnoughData(
2982 klass=self.__class__,
2983 decode_path=decode_path,
2987 sub_offset = offset + tlen + llen
2991 if v[:EOC_LEN].tobytes() == EOC:
2998 "chunk out of bounds",
2999 klass=self.__class__,
3000 decode_path=decode_path + (str(len(chunks) - 1),),
3001 offset=chunks[-1].offset,
3003 sub_decode_path = decode_path + (str(len(chunks)),)
3006 for _decode_path, chunk, v_tail in BitString().decode_evgen(
3009 decode_path=sub_decode_path,
3012 _ctx_immutable=False,
3014 yield _decode_path, chunk, v_tail
3016 _, chunk, v_tail = next(BitString().decode_evgen(
3019 decode_path=sub_decode_path,
3022 _ctx_immutable=False,
3027 "expected BitString encoded chunk",
3028 klass=self.__class__,
3029 decode_path=sub_decode_path,
3032 chunks.append(chunk)
3033 sub_offset += chunk.tlvlen
3034 vlen += chunk.tlvlen
3036 if len(chunks) == 0:
3039 klass=self.__class__,
3040 decode_path=decode_path,
3045 for chunk_i, chunk in enumerate(chunks[:-1]):
3046 if chunk.bit_len % 8 != 0:
3048 "BitString chunk is not multiple of 8 bits",
3049 klass=self.__class__,
3050 decode_path=decode_path + (str(chunk_i),),
3051 offset=chunk.offset,
3054 values.append(bytes(chunk))
3055 bit_len += chunk.bit_len
3056 chunk_last = chunks[-1]
3058 values.append(bytes(chunk_last))
3059 bit_len += chunk_last.bit_len
3060 obj = self.__class__(
3061 value=None if evgen_mode else (bit_len, b"".join(values)),
3064 default=self.default,
3065 optional=self.optional,
3067 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3070 obj._value = (bit_len, None)
3071 obj.lenindef = lenindef
3072 obj.ber_encoded = True
3073 yield decode_path, obj, (v[EOC_LEN:] if lenindef else v)
3076 return pp_console_row(next(self.pps()))
3078 def pps(self, decode_path=()):
3082 bit_len, blob = self._value
3083 value = "%d bits" % bit_len
3084 if len(self.specs) > 0 and blob is not None:
3085 blob = tuple(self.named)
3088 asn1_type_name=self.asn1_type_name,
3089 obj_name=self.__class__.__name__,
3090 decode_path=decode_path,
3093 optional=self.optional,
3094 default=self == self.default,
3095 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3096 expl=None if self._expl is None else tag_decode(self._expl),
3101 expl_offset=self.expl_offset if self.expled else None,
3102 expl_tlen=self.expl_tlen if self.expled else None,
3103 expl_llen=self.expl_llen if self.expled else None,
3104 expl_vlen=self.expl_vlen if self.expled else None,
3105 expl_lenindef=self.expl_lenindef,
3106 lenindef=self.lenindef,
3107 ber_encoded=self.ber_encoded,
3110 defined_by, defined = self.defined or (None, None)
3111 if defined_by is not None:
3113 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3115 for pp in self.pps_lenindef(decode_path):
3119 OctetStringState = namedtuple(
3121 BasicState._fields + (
3132 class OctetString(Obj):
3133 """``OCTET STRING`` binary string type
3135 >>> s = OctetString(b"hello world")
3136 OCTET STRING 11 bytes 68656c6c6f20776f726c64
3137 >>> s == OctetString(b"hello world")
3142 >>> OctetString(b"hello", bounds=(4, 4))
3143 Traceback (most recent call last):
3144 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
3145 >>> OctetString(b"hell", bounds=(4, 4))
3146 OCTET STRING 4 bytes 68656c6c
3150 Pay attention that OCTET STRING can be encoded both in primitive
3151 and constructed forms. Decoder always checks constructed form tag
3152 additionally to specified primitive one. If BER decoding is
3153 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
3154 of DER restrictions.
3156 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
3157 tag_default = tag_encode(4)
3158 asn1_type_name = "OCTET STRING"
3159 evgen_mode_skip_value = True
3173 :param value: set the value. Either binary type, or
3174 :py:class:`pyderasn.OctetString` object
3175 :param bounds: set ``(MIN, MAX)`` value size constraint.
3176 (-inf, +inf) by default
3177 :param bytes impl: override default tag with ``IMPLICIT`` one
3178 :param bytes expl: override default tag with ``EXPLICIT`` one
3179 :param default: set default value. Type same as in ``value``
3180 :param bool optional: is object ``OPTIONAL`` in sequence
3182 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
3184 self._bound_min, self._bound_max = getattr(
3188 ) if bounds is None else bounds
3189 if value is not None:
3190 self._value = self._value_sanitize(value)
3191 if default is not None:
3192 default = self._value_sanitize(default)
3193 self.default = self.__class__(
3198 if self._value is None:
3199 self._value = default
3201 tag_klass, _, tag_num = tag_decode(self.tag)
3202 self.tag_constructed = tag_encode(
3204 form=TagFormConstructed,
3208 def _value_sanitize(self, value):
3209 if value.__class__ == binary_type:
3211 elif issubclass(value.__class__, OctetString):
3212 value = value._value
3214 raise InvalidValueType((self.__class__, bytes))
3215 if not self._bound_min <= len(value) <= self._bound_max:
3216 raise BoundsError(self._bound_min, len(value), self._bound_max)
3221 return self._value is not None
3223 def __getstate__(self):
3224 return OctetStringState(
3240 self.tag_constructed,
3244 def __setstate__(self, state):
3245 super(OctetString, self).__setstate__(state)
3246 self._value = state.value
3247 self._bound_min = state.bound_min
3248 self._bound_max = state.bound_max
3249 self.tag_constructed = state.tag_constructed
3250 self.defined = state.defined
3252 def __bytes__(self):
3253 self._assert_ready()
3256 def __eq__(self, their):
3257 if their.__class__ == binary_type:
3258 return self._value == their
3259 if not issubclass(their.__class__, OctetString):
3262 self._value == their._value and
3263 self.tag == their.tag and
3264 self._expl == their._expl
3267 def __lt__(self, their):
3268 return self._value < their._value
3279 return self.__class__(
3282 (self._bound_min, self._bound_max)
3283 if bounds is None else bounds
3285 impl=self.tag if impl is None else impl,
3286 expl=self._expl if expl is None else expl,
3287 default=self.default if default is None else default,
3288 optional=self.optional if optional is None else optional,
3292 self._assert_ready()
3295 len_encode(len(self._value)),
3299 def _encode_cer(self, writer):
3300 octets = self._value
3301 if len(octets) <= 1000:
3302 write_full(writer, self._encode())
3304 write_full(writer, self.tag_constructed)
3305 write_full(writer, LENINDEF)
3306 for offset in six_xrange(0, (len(octets) // 1000) * 1000, 1000):
3307 write_full(writer, b"".join((
3308 OctetString.tag_default,
3310 octets[offset:offset + 1000],
3312 tail = octets[offset+1000:]
3314 write_full(writer, b"".join((
3315 OctetString.tag_default,
3316 len_encode(len(tail)),
3319 write_full(writer, EOC)
3321 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3323 t, tlen, lv = tag_strip(tlv)
3324 except DecodeError as err:
3325 raise err.__class__(
3327 klass=self.__class__,
3328 decode_path=decode_path,
3336 l, llen, v = len_decode(lv)
3337 except DecodeError as err:
3338 raise err.__class__(
3340 klass=self.__class__,
3341 decode_path=decode_path,
3345 raise NotEnoughData(
3346 "encoded length is longer than data",
3347 klass=self.__class__,
3348 decode_path=decode_path,
3351 v, tail = v[:l], v[l:]
3352 if evgen_mode and not self._bound_min <= len(v) <= self._bound_max:
3354 msg=str(BoundsError(self._bound_min, len(v), self._bound_max)),
3355 klass=self.__class__,
3356 decode_path=decode_path,
3360 obj = self.__class__(
3362 None if (evgen_mode and self.evgen_mode_skip_value)
3365 bounds=(self._bound_min, self._bound_max),
3368 default=self.default,
3369 optional=self.optional,
3370 _decoded=(offset, llen, l),
3373 except DecodeError as err:
3376 klass=self.__class__,
3377 decode_path=decode_path,
3380 except BoundsError as err:
3383 klass=self.__class__,
3384 decode_path=decode_path,
3387 yield decode_path, obj, tail
3389 if t != self.tag_constructed:
3391 klass=self.__class__,
3392 decode_path=decode_path,
3395 if not ctx.get("bered", False):
3397 "unallowed BER constructed encoding",
3398 klass=self.__class__,
3399 decode_path=decode_path,
3407 l, llen, v = len_decode(lv)
3408 except LenIndefForm:
3409 llen, l, v = 1, 0, lv[1:]
3411 except DecodeError as err:
3412 raise err.__class__(
3414 klass=self.__class__,
3415 decode_path=decode_path,
3419 raise NotEnoughData(
3420 "encoded length is longer than data",
3421 klass=self.__class__,
3422 decode_path=decode_path,
3427 sub_offset = offset + tlen + llen
3432 if v[:EOC_LEN].tobytes() == EOC:
3439 "chunk out of bounds",
3440 klass=self.__class__,
3441 decode_path=decode_path + (str(len(chunks) - 1),),
3442 offset=chunks[-1].offset,
3446 sub_decode_path = decode_path + (str(chunks_count),)
3447 for _decode_path, chunk, v_tail in OctetString().decode_evgen(
3450 decode_path=sub_decode_path,
3453 _ctx_immutable=False,
3455 yield _decode_path, chunk, v_tail
3456 if not chunk.ber_encoded:
3457 payload_len += chunk.vlen
3460 sub_decode_path = decode_path + (str(len(chunks)),)
3461 _, chunk, v_tail = next(OctetString().decode_evgen(
3464 decode_path=sub_decode_path,
3467 _ctx_immutable=False,
3470 chunks.append(chunk)
3473 "expected OctetString encoded chunk",
3474 klass=self.__class__,
3475 decode_path=sub_decode_path,
3478 sub_offset += chunk.tlvlen
3479 vlen += chunk.tlvlen
3481 if evgen_mode and not self._bound_min <= payload_len <= self._bound_max:
3483 msg=str(BoundsError(self._bound_min, payload_len, self._bound_max)),
3484 klass=self.__class__,
3485 decode_path=decode_path,
3489 obj = self.__class__(
3491 None if evgen_mode else
3492 b"".join(bytes(chunk) for chunk in chunks)
3494 bounds=(self._bound_min, self._bound_max),
3497 default=self.default,
3498 optional=self.optional,
3499 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3502 except DecodeError as err:
3505 klass=self.__class__,
3506 decode_path=decode_path,
3509 except BoundsError as err:
3512 klass=self.__class__,
3513 decode_path=decode_path,
3516 obj.lenindef = lenindef
3517 obj.ber_encoded = True
3518 yield decode_path, obj, (v[EOC_LEN:] if lenindef else v)
3521 return pp_console_row(next(self.pps()))
3523 def pps(self, decode_path=()):
3526 asn1_type_name=self.asn1_type_name,
3527 obj_name=self.__class__.__name__,
3528 decode_path=decode_path,
3529 value=("%d bytes" % len(self._value)) if self.ready else None,
3530 blob=self._value if self.ready else None,
3531 optional=self.optional,
3532 default=self == self.default,
3533 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3534 expl=None if self._expl is None else tag_decode(self._expl),
3539 expl_offset=self.expl_offset if self.expled else None,
3540 expl_tlen=self.expl_tlen if self.expled else None,
3541 expl_llen=self.expl_llen if self.expled else None,
3542 expl_vlen=self.expl_vlen if self.expled else None,
3543 expl_lenindef=self.expl_lenindef,
3544 lenindef=self.lenindef,
3545 ber_encoded=self.ber_encoded,
3548 defined_by, defined = self.defined or (None, None)
3549 if defined_by is not None:
3551 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3553 for pp in self.pps_lenindef(decode_path):
3557 NullState = namedtuple("NullState", BasicState._fields, **NAMEDTUPLE_KWARGS)
3561 """``NULL`` null object
3569 tag_default = tag_encode(5)
3570 asn1_type_name = "NULL"
3574 value=None, # unused, but Sequence passes it
3581 :param bytes impl: override default tag with ``IMPLICIT`` one
3582 :param bytes expl: override default tag with ``EXPLICIT`` one
3583 :param bool optional: is object ``OPTIONAL`` in sequence
3585 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3592 def __getstate__(self):
3608 def __eq__(self, their):
3609 if not issubclass(their.__class__, Null):
3612 self.tag == their.tag and
3613 self._expl == their._expl
3623 return self.__class__(
3624 impl=self.tag if impl is None else impl,
3625 expl=self._expl if expl is None else expl,
3626 optional=self.optional if optional is None else optional,
3630 return self.tag + len_encode(0)
3632 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3634 t, _, lv = tag_strip(tlv)
3635 except DecodeError as err:
3636 raise err.__class__(
3638 klass=self.__class__,
3639 decode_path=decode_path,
3644 klass=self.__class__,
3645 decode_path=decode_path,
3648 if tag_only: # pragma: no cover
3652 l, _, v = len_decode(lv)
3653 except DecodeError as err:
3654 raise err.__class__(
3656 klass=self.__class__,
3657 decode_path=decode_path,
3661 raise InvalidLength(
3662 "Null must have zero length",
3663 klass=self.__class__,
3664 decode_path=decode_path,
3667 obj = self.__class__(
3670 optional=self.optional,
3671 _decoded=(offset, 1, 0),
3673 yield decode_path, obj, v
3676 return pp_console_row(next(self.pps()))
3678 def pps(self, decode_path=()):
3681 asn1_type_name=self.asn1_type_name,
3682 obj_name=self.__class__.__name__,
3683 decode_path=decode_path,
3684 optional=self.optional,
3685 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3686 expl=None if self._expl is None else tag_decode(self._expl),
3691 expl_offset=self.expl_offset if self.expled else None,
3692 expl_tlen=self.expl_tlen if self.expled else None,
3693 expl_llen=self.expl_llen if self.expled else None,
3694 expl_vlen=self.expl_vlen if self.expled else None,
3695 expl_lenindef=self.expl_lenindef,
3698 for pp in self.pps_lenindef(decode_path):
3702 ObjectIdentifierState = namedtuple(
3703 "ObjectIdentifierState",
3704 BasicState._fields + ("value", "defines"),
3709 class ObjectIdentifier(Obj):
3710 """``OBJECT IDENTIFIER`` OID type
3712 >>> oid = ObjectIdentifier((1, 2, 3))
3713 OBJECT IDENTIFIER 1.2.3
3714 >>> oid == ObjectIdentifier("1.2.3")
3720 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3721 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3723 >>> str(ObjectIdentifier((3, 1)))
3724 Traceback (most recent call last):
3725 pyderasn.InvalidOID: unacceptable first arc value
3727 __slots__ = ("defines",)
3728 tag_default = tag_encode(6)
3729 asn1_type_name = "OBJECT IDENTIFIER"
3742 :param value: set the value. Either tuples of integers,
3743 string of "."-concatenated integers, or
3744 :py:class:`pyderasn.ObjectIdentifier` object
3745 :param defines: sequence of tuples. Each tuple has two elements.
3746 First one is relative to current one decode
3747 path, aiming to the field defined by that OID.
3748 Read about relative path in
3749 :py:func:`pyderasn.abs_decode_path`. Second
3750 tuple element is ``{OID: pyderasn.Obj()}``
3751 dictionary, mapping between current OID value
3752 and structure applied to defined field.
3753 :ref:`Read about DEFINED BY <definedby>`
3754 :param bytes impl: override default tag with ``IMPLICIT`` one
3755 :param bytes expl: override default tag with ``EXPLICIT`` one
3756 :param default: set default value. Type same as in ``value``
3757 :param bool optional: is object ``OPTIONAL`` in sequence
3759 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3761 if value is not None:
3762 self._value = self._value_sanitize(value)
3763 if default is not None:
3764 default = self._value_sanitize(default)
3765 self.default = self.__class__(
3770 if self._value is None:
3771 self._value = default
3772 self.defines = defines
3774 def __add__(self, their):
3775 if their.__class__ == tuple:
3776 return self.__class__(self._value + their)
3777 if isinstance(their, self.__class__):
3778 return self.__class__(self._value + their._value)
3779 raise InvalidValueType((self.__class__, tuple))
3781 def _value_sanitize(self, value):
3782 if issubclass(value.__class__, ObjectIdentifier):
3784 if isinstance(value, string_types):
3786 value = tuple(pureint(arc) for arc in value.split("."))
3788 raise InvalidOID("unacceptable arcs values")
3789 if value.__class__ == tuple:
3791 raise InvalidOID("less than 2 arcs")
3792 first_arc = value[0]
3793 if first_arc in (0, 1):
3794 if not (0 <= value[1] <= 39):
3795 raise InvalidOID("second arc is too wide")
3796 elif first_arc == 2:
3799 raise InvalidOID("unacceptable first arc value")
3800 if not all(arc >= 0 for arc in value):
3801 raise InvalidOID("negative arc value")
3803 raise InvalidValueType((self.__class__, str, tuple))
3807 return self._value is not None
3809 def __getstate__(self):
3810 return ObjectIdentifierState(
3827 def __setstate__(self, state):
3828 super(ObjectIdentifier, self).__setstate__(state)
3829 self._value = state.value
3830 self.defines = state.defines
3833 self._assert_ready()
3834 return iter(self._value)
3837 return ".".join(str(arc) for arc in self._value or ())
3840 self._assert_ready()
3843 bytes(self._expl or b"") +
3844 str(self._value).encode("ascii"),
3847 def __eq__(self, their):
3848 if their.__class__ == tuple:
3849 return self._value == their
3850 if not issubclass(their.__class__, ObjectIdentifier):
3853 self.tag == their.tag and
3854 self._expl == their._expl and
3855 self._value == their._value
3858 def __lt__(self, their):
3859 return self._value < their._value
3870 return self.__class__(
3872 defines=self.defines if defines is None else defines,
3873 impl=self.tag if impl is None else impl,
3874 expl=self._expl if expl is None else expl,
3875 default=self.default if default is None else default,
3876 optional=self.optional if optional is None else optional,
3880 self._assert_ready()
3882 first_value = value[1]
3883 first_arc = value[0]
3886 elif first_arc == 1:
3888 elif first_arc == 2:
3890 else: # pragma: no cover
3891 raise RuntimeError("invalid arc is stored")
3892 octets = [zero_ended_encode(first_value)]
3893 for arc in value[2:]:
3894 octets.append(zero_ended_encode(arc))
3895 v = b"".join(octets)
3896 return b"".join((self.tag, len_encode(len(v)), v))
3898 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3900 t, _, lv = tag_strip(tlv)
3901 except DecodeError as err:
3902 raise err.__class__(
3904 klass=self.__class__,
3905 decode_path=decode_path,
3910 klass=self.__class__,
3911 decode_path=decode_path,
3914 if tag_only: # pragma: no cover
3918 l, llen, v = len_decode(lv)
3919 except DecodeError as err:
3920 raise err.__class__(
3922 klass=self.__class__,
3923 decode_path=decode_path,
3927 raise NotEnoughData(
3928 "encoded length is longer than data",
3929 klass=self.__class__,
3930 decode_path=decode_path,
3934 raise NotEnoughData(
3936 klass=self.__class__,
3937 decode_path=decode_path,
3940 v, tail = v[:l], v[l:]
3947 octet = indexbytes(v, i)
3948 if i == 0 and octet == 0x80:
3949 if ctx.get("bered", False):
3952 raise DecodeError("non normalized arc encoding")
3953 arc = (arc << 7) | (octet & 0x7F)
3954 if octet & 0x80 == 0:
3962 klass=self.__class__,
3963 decode_path=decode_path,
3967 second_arc = arcs[0]
3968 if 0 <= second_arc <= 39:
3970 elif 40 <= second_arc <= 79:
3976 obj = self.__class__(
3977 value=tuple([first_arc, second_arc] + arcs[1:]),
3980 default=self.default,
3981 optional=self.optional,
3982 _decoded=(offset, llen, l),
3985 obj.ber_encoded = True
3986 yield decode_path, obj, tail
3989 return pp_console_row(next(self.pps()))
3991 def pps(self, decode_path=()):
3994 asn1_type_name=self.asn1_type_name,
3995 obj_name=self.__class__.__name__,
3996 decode_path=decode_path,
3997 value=str(self) if self.ready else None,
3998 optional=self.optional,
3999 default=self == self.default,
4000 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4001 expl=None if self._expl is None else tag_decode(self._expl),
4006 expl_offset=self.expl_offset if self.expled else None,
4007 expl_tlen=self.expl_tlen if self.expled else None,
4008 expl_llen=self.expl_llen if self.expled else None,
4009 expl_vlen=self.expl_vlen if self.expled else None,
4010 expl_lenindef=self.expl_lenindef,
4011 ber_encoded=self.ber_encoded,
4014 for pp in self.pps_lenindef(decode_path):
4018 class Enumerated(Integer):
4019 """``ENUMERATED`` integer type
4021 This type is identical to :py:class:`pyderasn.Integer`, but requires
4022 schema to be specified and does not accept values missing from it.
4025 tag_default = tag_encode(10)
4026 asn1_type_name = "ENUMERATED"
4037 bounds=None, # dummy argument, workability for Integer.decode
4039 super(Enumerated, self).__init__(
4040 value, bounds, impl, expl, default, optional, _specs, _decoded,
4042 if len(self.specs) == 0:
4043 raise ValueError("schema must be specified")
4045 def _value_sanitize(self, value):
4046 if isinstance(value, self.__class__):
4047 value = value._value
4048 elif isinstance(value, integer_types):
4049 for _value in itervalues(self.specs):
4054 "unknown integer value: %s" % value,
4055 klass=self.__class__,
4057 elif isinstance(value, string_types):
4058 value = self.specs.get(value)
4060 raise ObjUnknown("integer value: %s" % value)
4062 raise InvalidValueType((self.__class__, int, str))
4074 return self.__class__(
4076 impl=self.tag if impl is None else impl,
4077 expl=self._expl if expl is None else expl,
4078 default=self.default if default is None else default,
4079 optional=self.optional if optional is None else optional,
4084 def escape_control_unicode(c):
4085 if unicat(c)[0] == "C":
4086 c = repr(c).lstrip("u").strip("'")
4090 class CommonString(OctetString):
4091 """Common class for all strings
4093 Everything resembles :py:class:`pyderasn.OctetString`, except
4094 ability to deal with unicode text strings.
4096 >>> hexenc("привет мир".encode("utf-8"))
4097 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
4098 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
4100 >>> s = UTF8String("привет мир")
4101 UTF8String UTF8String привет мир
4103 'привет мир'
4104 >>> hexenc(bytes(s))
4105 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
4107 >>> PrintableString("привет мир")
4108 Traceback (most recent call last):
4109 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
4111 >>> BMPString("ада", bounds=(2, 2))
4112 Traceback (most recent call last):
4113 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
4114 >>> s = BMPString("ад", bounds=(2, 2))
4117 >>> hexenc(bytes(s))
4125 * - :py:class:`pyderasn.UTF8String`
4127 * - :py:class:`pyderasn.NumericString`
4129 * - :py:class:`pyderasn.PrintableString`
4131 * - :py:class:`pyderasn.TeletexString`
4133 * - :py:class:`pyderasn.T61String`
4135 * - :py:class:`pyderasn.VideotexString`
4137 * - :py:class:`pyderasn.IA5String`
4139 * - :py:class:`pyderasn.GraphicString`
4141 * - :py:class:`pyderasn.VisibleString`
4143 * - :py:class:`pyderasn.ISO646String`
4145 * - :py:class:`pyderasn.GeneralString`
4147 * - :py:class:`pyderasn.UniversalString`
4149 * - :py:class:`pyderasn.BMPString`
4154 def _value_sanitize(self, value):
4156 value_decoded = None
4157 if isinstance(value, self.__class__):
4158 value_raw = value._value
4159 elif value.__class__ == text_type:
4160 value_decoded = value
4161 elif value.__class__ == binary_type:
4164 raise InvalidValueType((self.__class__, text_type, binary_type))
4167 value_decoded.encode(self.encoding)
4168 if value_raw is None else value_raw
4171 value_raw.decode(self.encoding)
4172 if value_decoded is None else value_decoded
4174 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4175 raise DecodeError(str(err))
4176 if not self._bound_min <= len(value_decoded) <= self._bound_max:
4184 def __eq__(self, their):
4185 if their.__class__ == binary_type:
4186 return self._value == their
4187 if their.__class__ == text_type:
4188 return self._value == their.encode(self.encoding)
4189 if not isinstance(their, self.__class__):
4192 self._value == their._value and
4193 self.tag == their.tag and
4194 self._expl == their._expl
4197 def __unicode__(self):
4199 return self._value.decode(self.encoding)
4200 return text_type(self._value)
4203 return pp_console_row(next(self.pps(no_unicode=PY2)))
4205 def pps(self, decode_path=(), no_unicode=False):
4209 hexenc(bytes(self)) if no_unicode else
4210 "".join(escape_control_unicode(c) for c in self.__unicode__())
4214 asn1_type_name=self.asn1_type_name,
4215 obj_name=self.__class__.__name__,
4216 decode_path=decode_path,
4218 optional=self.optional,
4219 default=self == self.default,
4220 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4221 expl=None if self._expl is None else tag_decode(self._expl),
4226 expl_offset=self.expl_offset if self.expled else None,
4227 expl_tlen=self.expl_tlen if self.expled else None,
4228 expl_llen=self.expl_llen if self.expled else None,
4229 expl_vlen=self.expl_vlen if self.expled else None,
4230 expl_lenindef=self.expl_lenindef,
4231 ber_encoded=self.ber_encoded,
4234 for pp in self.pps_lenindef(decode_path):
4238 class UTF8String(CommonString):
4240 tag_default = tag_encode(12)
4242 asn1_type_name = "UTF8String"
4245 class AllowableCharsMixin(object):
4247 def allowable_chars(self):
4249 return self._allowable_chars
4250 return frozenset(six_unichr(c) for c in self._allowable_chars)
4253 class NumericString(AllowableCharsMixin, CommonString):
4256 Its value is properly sanitized: only ASCII digits with spaces can
4259 >>> NumericString().allowable_chars
4260 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
4263 tag_default = tag_encode(18)
4265 asn1_type_name = "NumericString"
4266 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
4268 def _value_sanitize(self, value):
4269 value = super(NumericString, self)._value_sanitize(value)
4270 if not frozenset(value) <= self._allowable_chars:
4271 raise DecodeError("non-numeric value")
4275 PrintableStringState = namedtuple(
4276 "PrintableStringState",
4277 OctetStringState._fields + ("allowable_chars",),
4282 class PrintableString(AllowableCharsMixin, CommonString):
4285 Its value is properly sanitized: see X.680 41.4 table 10.
4287 >>> PrintableString().allowable_chars
4288 frozenset([' ', "'", ..., 'z'])
4289 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4290 PrintableString PrintableString foo*bar
4291 >>> obj.allow_asterisk, obj.allow_ampersand
4295 tag_default = tag_encode(19)
4297 asn1_type_name = "PrintableString"
4298 _allowable_chars = frozenset(
4299 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4301 _asterisk = frozenset("*".encode("ascii"))
4302 _ampersand = frozenset("&".encode("ascii"))
4314 allow_asterisk=False,
4315 allow_ampersand=False,
4318 :param allow_asterisk: allow asterisk character
4319 :param allow_ampersand: allow ampersand character
4322 self._allowable_chars |= self._asterisk
4324 self._allowable_chars |= self._ampersand
4325 super(PrintableString, self).__init__(
4326 value, bounds, impl, expl, default, optional, _decoded, ctx,
4330 def allow_asterisk(self):
4331 """Is asterisk character allowed?
4333 return self._asterisk <= self._allowable_chars
4336 def allow_ampersand(self):
4337 """Is ampersand character allowed?
4339 return self._ampersand <= self._allowable_chars
4341 def _value_sanitize(self, value):
4342 value = super(PrintableString, self)._value_sanitize(value)
4343 if not frozenset(value) <= self._allowable_chars:
4344 raise DecodeError("non-printable value")
4347 def __getstate__(self):
4348 return PrintableStringState(
4349 *super(PrintableString, self).__getstate__(),
4350 **{"allowable_chars": self._allowable_chars}
4353 def __setstate__(self, state):
4354 super(PrintableString, self).__setstate__(state)
4355 self._allowable_chars = state.allowable_chars
4366 return self.__class__(
4369 (self._bound_min, self._bound_max)
4370 if bounds is None else bounds
4372 impl=self.tag if impl is None else impl,
4373 expl=self._expl if expl is None else expl,
4374 default=self.default if default is None else default,
4375 optional=self.optional if optional is None else optional,
4376 allow_asterisk=self.allow_asterisk,
4377 allow_ampersand=self.allow_ampersand,
4381 class TeletexString(CommonString):
4383 tag_default = tag_encode(20)
4385 asn1_type_name = "TeletexString"
4388 class T61String(TeletexString):
4390 asn1_type_name = "T61String"
4393 class VideotexString(CommonString):
4395 tag_default = tag_encode(21)
4396 encoding = "iso-8859-1"
4397 asn1_type_name = "VideotexString"
4400 class IA5String(CommonString):
4402 tag_default = tag_encode(22)
4404 asn1_type_name = "IA5"
4407 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4408 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4409 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4412 class VisibleString(CommonString):
4414 tag_default = tag_encode(26)
4416 asn1_type_name = "VisibleString"
4419 UTCTimeState = namedtuple(
4421 OctetStringState._fields + ("ber_raw",),
4426 def str_to_time_fractions(value):
4428 year, v = (v // 10**10), (v % 10**10)
4429 month, v = (v // 10**8), (v % 10**8)
4430 day, v = (v // 10**6), (v % 10**6)
4431 hour, v = (v // 10**4), (v % 10**4)
4432 minute, second = (v // 100), (v % 100)
4433 return year, month, day, hour, minute, second
4436 class UTCTime(VisibleString):
4437 """``UTCTime`` datetime type
4439 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4440 UTCTime UTCTime 2017-09-30T22:07:50
4446 datetime.datetime(2017, 9, 30, 22, 7, 50)
4447 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4448 datetime.datetime(1957, 9, 30, 22, 7, 50)
4450 If BER encoded value was met, then ``ber_raw`` attribute will hold
4451 its raw representation.
4455 Pay attention that UTCTime can not hold full year, so all years
4456 having < 50 years are treated as 20xx, 19xx otherwise, according
4457 to X.509 recommendation.
4461 No strict validation of UTC offsets are made, but very crude:
4463 * minutes are not exceeding 60
4464 * offset value is not exceeding 14 hours
4466 __slots__ = ("ber_raw",)
4467 tag_default = tag_encode(23)
4469 asn1_type_name = "UTCTime"
4470 evgen_mode_skip_value = False
4480 bounds=None, # dummy argument, workability for OctetString.decode
4484 :param value: set the value. Either datetime type, or
4485 :py:class:`pyderasn.UTCTime` object
4486 :param bytes impl: override default tag with ``IMPLICIT`` one
4487 :param bytes expl: override default tag with ``EXPLICIT`` one
4488 :param default: set default value. Type same as in ``value``
4489 :param bool optional: is object ``OPTIONAL`` in sequence
4491 super(UTCTime, self).__init__(
4492 None, None, impl, expl, None, optional, _decoded, ctx,
4496 if value is not None:
4497 self._value, self.ber_raw = self._value_sanitize(value, ctx)
4498 self.ber_encoded = self.ber_raw is not None
4499 if default is not None:
4500 default, _ = self._value_sanitize(default)
4501 self.default = self.__class__(
4506 if self._value is None:
4507 self._value = default
4509 self.optional = optional
4511 def _strptime_bered(self, value):
4512 year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
4515 raise ValueError("no timezone")
4516 year += 2000 if year < 50 else 1900
4517 decoded = datetime(year, month, day, hour, minute)
4519 if value[-1] == "Z":
4523 raise ValueError("invalid UTC offset")
4524 if value[-5] == "-":
4526 elif value[-5] == "+":
4529 raise ValueError("invalid UTC offset")
4530 v = pureint(value[-4:])
4531 offset, v = (60 * (v % 100)), v // 100
4533 raise ValueError("invalid UTC offset minutes")
4535 if offset > 14 * 3600:
4536 raise ValueError("too big UTC offset")
4540 return offset, decoded
4542 raise ValueError("invalid UTC offset seconds")
4543 seconds = pureint(value)
4545 raise ValueError("invalid seconds value")
4546 return offset, decoded + timedelta(seconds=seconds)
4548 def _strptime(self, value):
4549 # datetime.strptime's format: %y%m%d%H%M%SZ
4550 if len(value) != LEN_YYMMDDHHMMSSZ:
4551 raise ValueError("invalid UTCTime length")
4552 if value[-1] != "Z":
4553 raise ValueError("non UTC timezone")
4554 year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
4555 year += 2000 if year < 50 else 1900
4556 return datetime(year, month, day, hour, minute, second)
4558 def _dt_sanitize(self, value):
4559 if value.year < 1950 or value.year > 2049:
4560 raise ValueError("UTCTime can hold only 1950-2049 years")
4561 return value.replace(microsecond=0)
4563 def _value_sanitize(self, value, ctx=None):
4564 if value.__class__ == binary_type:
4566 value_decoded = value.decode("ascii")
4567 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4568 raise DecodeError("invalid UTCTime encoding: %r" % err)
4571 return self._strptime(value_decoded), None
4572 except (TypeError, ValueError) as _err:
4574 if (ctx is not None) and ctx.get("bered", False):
4576 offset, _value = self._strptime_bered(value_decoded)
4577 _value = _value - timedelta(seconds=offset)
4578 return self._dt_sanitize(_value), value
4579 except (TypeError, ValueError, OverflowError) as _err:
4582 "invalid %s format: %r" % (self.asn1_type_name, err),
4583 klass=self.__class__,
4585 if isinstance(value, self.__class__):
4586 return value._value, None
4587 if value.__class__ == datetime:
4588 return self._dt_sanitize(value), None
4589 raise InvalidValueType((self.__class__, datetime))
4591 def _pp_value(self):
4593 value = self._value.isoformat()
4594 if self.ber_encoded:
4595 value += " (%s)" % self.ber_raw
4598 def __unicode__(self):
4600 value = self._value.isoformat()
4601 if self.ber_encoded:
4602 value += " (%s)" % self.ber_raw
4604 return text_type(self._pp_value())
4606 def __getstate__(self):
4607 return UTCTimeState(
4608 *super(UTCTime, self).__getstate__(),
4609 **{"ber_raw": self.ber_raw}
4612 def __setstate__(self, state):
4613 super(UTCTime, self).__setstate__(state)
4614 self.ber_raw = state.ber_raw
4616 def __bytes__(self):
4617 self._assert_ready()
4618 return self._encode_time()
4620 def __eq__(self, their):
4621 if their.__class__ == binary_type:
4622 return self._encode_time() == their
4623 if their.__class__ == datetime:
4624 return self.todatetime() == their
4625 if not isinstance(their, self.__class__):
4628 self._value == their._value and
4629 self.tag == their.tag and
4630 self._expl == their._expl
4633 def _encode_time(self):
4634 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4637 self._assert_ready()
4638 value = self._encode_time()
4639 return b"".join((self.tag, len_encode(len(value)), value))
4641 def _encode_cer(self, writer):
4642 write_full(writer, self._encode())
4644 def todatetime(self):
4648 return pp_console_row(next(self.pps()))
4650 def pps(self, decode_path=()):
4653 asn1_type_name=self.asn1_type_name,
4654 obj_name=self.__class__.__name__,
4655 decode_path=decode_path,
4656 value=self._pp_value(),
4657 optional=self.optional,
4658 default=self == self.default,
4659 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4660 expl=None if self._expl is None else tag_decode(self._expl),
4665 expl_offset=self.expl_offset if self.expled else None,
4666 expl_tlen=self.expl_tlen if self.expled else None,
4667 expl_llen=self.expl_llen if self.expled else None,
4668 expl_vlen=self.expl_vlen if self.expled else None,
4669 expl_lenindef=self.expl_lenindef,
4670 ber_encoded=self.ber_encoded,
4673 for pp in self.pps_lenindef(decode_path):
4677 class GeneralizedTime(UTCTime):
4678 """``GeneralizedTime`` datetime type
4680 This type is similar to :py:class:`pyderasn.UTCTime`.
4682 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4683 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4685 '20170930220750.000123Z'
4686 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4687 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4691 Only microsecond fractions are supported in DER encoding.
4692 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4693 higher precision values.
4697 BER encoded data can loss information (accuracy) during decoding
4698 because of float transformations.
4702 Local times (without explicit timezone specification) are treated
4703 as UTC one, no transformations are made.
4707 Zero year is unsupported.
4710 tag_default = tag_encode(24)
4711 asn1_type_name = "GeneralizedTime"
4713 def _dt_sanitize(self, value):
4716 def _strptime_bered(self, value):
4717 if len(value) < 4 + 3 * 2:
4718 raise ValueError("invalid GeneralizedTime")
4719 year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
4720 decoded = datetime(year, month, day, hour)
4721 offset, value = 0, value[10:]
4723 return offset, decoded
4724 if value[-1] == "Z":
4727 for char, sign in (("-", -1), ("+", 1)):
4728 idx = value.rfind(char)
4731 offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
4732 v = pureint(offset_raw)
4733 if len(offset_raw) == 4:
4734 offset, v = (60 * (v % 100)), v // 100
4736 raise ValueError("invalid UTC offset minutes")
4737 elif len(offset_raw) == 2:
4740 raise ValueError("invalid UTC offset")
4742 if offset > 14 * 3600:
4743 raise ValueError("too big UTC offset")
4747 return offset, decoded
4748 if value[0] in DECIMAL_SIGNS:
4750 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4753 raise ValueError("stripped minutes")
4754 decoded += timedelta(seconds=60 * pureint(value[:2]))
4757 return offset, decoded
4758 if value[0] in DECIMAL_SIGNS:
4760 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4763 raise ValueError("stripped seconds")
4764 decoded += timedelta(seconds=pureint(value[:2]))
4767 return offset, decoded
4768 if value[0] not in DECIMAL_SIGNS:
4769 raise ValueError("invalid format after seconds")
4771 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4774 def _strptime(self, value):
4776 if l == LEN_YYYYMMDDHHMMSSZ:
4777 # datetime.strptime's format: %Y%m%d%H%M%SZ
4778 if value[-1] != "Z":
4779 raise ValueError("non UTC timezone")
4780 return datetime(*str_to_time_fractions(value[:-1]))
4781 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4782 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4783 if value[-1] != "Z":
4784 raise ValueError("non UTC timezone")
4785 if value[14] != ".":
4786 raise ValueError("no fractions separator")
4789 raise ValueError("trailing zero")
4792 raise ValueError("only microsecond fractions are supported")
4793 us = pureint(us + ("0" * (6 - us_len)))
4794 year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
4795 return datetime(year, month, day, hour, minute, second, us)
4796 raise ValueError("invalid GeneralizedTime length")
4798 def _encode_time(self):
4800 encoded = value.strftime("%Y%m%d%H%M%S")
4801 if value.microsecond > 0:
4802 encoded += (".%06d" % value.microsecond).rstrip("0")
4803 return (encoded + "Z").encode("ascii")
4806 class GraphicString(CommonString):
4808 tag_default = tag_encode(25)
4809 encoding = "iso-8859-1"
4810 asn1_type_name = "GraphicString"
4813 class ISO646String(VisibleString):
4815 asn1_type_name = "ISO646String"
4818 class GeneralString(CommonString):
4820 tag_default = tag_encode(27)
4821 encoding = "iso-8859-1"
4822 asn1_type_name = "GeneralString"
4825 class UniversalString(CommonString):
4827 tag_default = tag_encode(28)
4828 encoding = "utf-32-be"
4829 asn1_type_name = "UniversalString"
4832 class BMPString(CommonString):
4834 tag_default = tag_encode(30)
4835 encoding = "utf-16-be"
4836 asn1_type_name = "BMPString"
4839 ChoiceState = namedtuple(
4841 BasicState._fields + ("specs", "value",),
4847 """``CHOICE`` special type
4851 class GeneralName(Choice):
4853 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4854 ("dNSName", IA5String(impl=tag_ctxp(2))),
4857 >>> gn = GeneralName()
4859 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4860 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4861 >>> gn["dNSName"] = IA5String("bar.baz")
4862 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4863 >>> gn["rfc822Name"]
4866 [2] IA5String IA5 bar.baz
4869 >>> gn.value == gn["dNSName"]
4872 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4874 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4875 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4877 __slots__ = ("specs",)
4879 asn1_type_name = "CHOICE"
4892 :param value: set the value. Either ``(choice, value)`` tuple, or
4893 :py:class:`pyderasn.Choice` object
4894 :param bytes impl: can not be set, do **not** use it
4895 :param bytes expl: override default tag with ``EXPLICIT`` one
4896 :param default: set default value. Type same as in ``value``
4897 :param bool optional: is object ``OPTIONAL`` in sequence
4899 if impl is not None:
4900 raise ValueError("no implicit tag allowed for CHOICE")
4901 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4903 schema = getattr(self, "schema", ())
4904 if len(schema) == 0:
4905 raise ValueError("schema must be specified")
4907 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
4910 if value is not None:
4911 self._value = self._value_sanitize(value)
4912 if default is not None:
4913 default_value = self._value_sanitize(default)
4914 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4915 default_obj.specs = self.specs
4916 default_obj._value = default_value
4917 self.default = default_obj
4919 self._value = copy(default_obj._value)
4920 if self._expl is not None:
4921 tag_class, _, tag_num = tag_decode(self._expl)
4922 self._tag_order = (tag_class, tag_num)
4924 def _value_sanitize(self, value):
4925 if (value.__class__ == tuple) and len(value) == 2:
4927 spec = self.specs.get(choice)
4929 raise ObjUnknown(choice)
4930 if not isinstance(obj, spec.__class__):
4931 raise InvalidValueType((spec,))
4932 return (choice, spec(obj))
4933 if isinstance(value, self.__class__):
4935 raise InvalidValueType((self.__class__, tuple))
4939 return self._value is not None and self._value[1].ready
4943 return self.expl_lenindef or (
4944 (self._value is not None) and
4945 self._value[1].bered
4948 def __getstate__(self):
4966 def __setstate__(self, state):
4967 super(Choice, self).__setstate__(state)
4968 self.specs = state.specs
4969 self._value = state.value
4971 def __eq__(self, their):
4972 if (their.__class__ == tuple) and len(their) == 2:
4973 return self._value == their
4974 if not isinstance(their, self.__class__):
4977 self.specs == their.specs and
4978 self._value == their._value
4988 return self.__class__(
4991 expl=self._expl if expl is None else expl,
4992 default=self.default if default is None else default,
4993 optional=self.optional if optional is None else optional,
4998 """Name of the choice
5000 self._assert_ready()
5001 return self._value[0]
5005 """Value of underlying choice
5007 self._assert_ready()
5008 return self._value[1]
5011 def tag_order(self):
5012 self._assert_ready()
5013 return self._value[1].tag_order if self._tag_order is None else self._tag_order
5016 def tag_order_cer(self):
5017 return min(v.tag_order_cer for v in itervalues(self.specs))
5019 def __getitem__(self, key):
5020 if key not in self.specs:
5021 raise ObjUnknown(key)
5022 if self._value is None:
5024 choice, value = self._value
5029 def __setitem__(self, key, value):
5030 spec = self.specs.get(key)
5032 raise ObjUnknown(key)
5033 if not isinstance(value, spec.__class__):
5034 raise InvalidValueType((spec.__class__,))
5035 self._value = (key, spec(value))
5043 return self._value[1].decoded if self.ready else False
5046 self._assert_ready()
5047 return self._value[1].encode()
5049 def _encode_cer(self, writer):
5050 self._assert_ready()
5051 self._value[1].encode_cer(writer)
5053 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5054 for choice, spec in iteritems(self.specs):
5055 sub_decode_path = decode_path + (choice,)
5061 decode_path=sub_decode_path,
5064 _ctx_immutable=False,
5071 klass=self.__class__,
5072 decode_path=decode_path,
5075 if tag_only: # pragma: no cover
5079 for _decode_path, value, tail in spec.decode_evgen(
5083 decode_path=sub_decode_path,
5085 _ctx_immutable=False,
5087 yield _decode_path, value, tail
5089 _, value, tail = next(spec.decode_evgen(
5093 decode_path=sub_decode_path,
5095 _ctx_immutable=False,
5098 obj = self.__class__(
5101 default=self.default,
5102 optional=self.optional,
5103 _decoded=(offset, 0, value.fulllen),
5105 obj._value = (choice, value)
5106 yield decode_path, obj, tail
5109 value = pp_console_row(next(self.pps()))
5111 value = "%s[%r]" % (value, self.value)
5114 def pps(self, decode_path=()):
5117 asn1_type_name=self.asn1_type_name,
5118 obj_name=self.__class__.__name__,
5119 decode_path=decode_path,
5120 value=self.choice if self.ready else None,
5121 optional=self.optional,
5122 default=self == self.default,
5123 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5124 expl=None if self._expl is None else tag_decode(self._expl),
5129 expl_lenindef=self.expl_lenindef,
5133 yield self.value.pps(decode_path=decode_path + (self.choice,))
5134 for pp in self.pps_lenindef(decode_path):
5138 class PrimitiveTypes(Choice):
5139 """Predefined ``CHOICE`` for all generic primitive types
5141 It could be useful for general decoding of some unspecified values:
5143 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
5144 OCTET STRING 3 bytes 666f6f
5145 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
5149 schema = tuple((klass.__name__, klass()) for klass in (
5173 AnyState = namedtuple(
5175 BasicState._fields + ("value", "defined"),
5181 """``ANY`` special type
5183 >>> Any(Integer(-123))
5184 ANY INTEGER -123 (0X:7B)
5185 >>> a = Any(OctetString(b"hello world").encode())
5186 ANY 040b68656c6c6f20776f726c64
5187 >>> hexenc(bytes(a))
5188 b'0x040x0bhello world'
5190 __slots__ = ("defined",)
5191 tag_default = tag_encode(0)
5192 asn1_type_name = "ANY"
5202 :param value: set the value. Either any kind of pyderasn's
5203 **ready** object, or bytes. Pay attention that
5204 **no** validation is performed if raw binary value
5205 is valid TLV, except just tag decoding
5206 :param bytes expl: override default tag with ``EXPLICIT`` one
5207 :param bool optional: is object ``OPTIONAL`` in sequence
5209 super(Any, self).__init__(None, expl, None, optional, _decoded)
5213 value = self._value_sanitize(value)
5215 if self._expl is None:
5216 if value.__class__ == binary_type:
5217 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5219 tag_class, tag_num = value.tag_order
5221 tag_class, _, tag_num = tag_decode(self._expl)
5222 self._tag_order = (tag_class, tag_num)
5225 def _value_sanitize(self, value):
5226 if value.__class__ == binary_type:
5228 raise ValueError("Any value can not be empty")
5230 if isinstance(value, self.__class__):
5232 if not isinstance(value, Obj):
5233 raise InvalidValueType((self.__class__, Obj, binary_type))
5238 return self._value is not None
5241 def tag_order(self):
5242 self._assert_ready()
5243 return self._tag_order
5247 if self.expl_lenindef or self.lenindef:
5249 if self.defined is None:
5251 return self.defined[1].bered
5253 def __getstate__(self):
5271 def __setstate__(self, state):
5272 super(Any, self).__setstate__(state)
5273 self._value = state.value
5274 self.defined = state.defined
5276 def __eq__(self, their):
5277 if their.__class__ == binary_type:
5278 if self._value.__class__ == binary_type:
5279 return self._value == their
5280 return self._value.encode() == their
5281 if issubclass(their.__class__, Any):
5282 if self.ready and their.ready:
5283 return bytes(self) == bytes(their)
5284 return self.ready == their.ready
5293 return self.__class__(
5295 expl=self._expl if expl is None else expl,
5296 optional=self.optional if optional is None else optional,
5299 def __bytes__(self):
5300 self._assert_ready()
5302 if value.__class__ == binary_type:
5304 return self._value.encode()
5311 self._assert_ready()
5313 if value.__class__ == binary_type:
5315 return value.encode()
5317 def _encode_cer(self, writer):
5318 self._assert_ready()
5320 if value.__class__ == binary_type:
5321 write_full(writer, value)
5323 value.encode_cer(writer)
5325 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5327 t, tlen, lv = tag_strip(tlv)
5328 except DecodeError as err:
5329 raise err.__class__(
5331 klass=self.__class__,
5332 decode_path=decode_path,
5336 l, llen, v = len_decode(lv)
5337 except LenIndefForm as err:
5338 if not ctx.get("bered", False):
5339 raise err.__class__(
5341 klass=self.__class__,
5342 decode_path=decode_path,
5345 llen, vlen, v = 1, 0, lv[1:]
5346 sub_offset = offset + tlen + llen
5348 while v[:EOC_LEN].tobytes() != EOC:
5349 chunk, v = Any().decode(
5352 decode_path=decode_path + (str(chunk_i),),
5355 _ctx_immutable=False,
5357 vlen += chunk.tlvlen
5358 sub_offset += chunk.tlvlen
5360 tlvlen = tlen + llen + vlen + EOC_LEN
5361 obj = self.__class__(
5362 value=None if evgen_mode else tlv[:tlvlen].tobytes(),
5364 optional=self.optional,
5365 _decoded=(offset, 0, tlvlen),
5368 obj.tag = t.tobytes()
5369 yield decode_path, obj, v[EOC_LEN:]
5371 except DecodeError as err:
5372 raise err.__class__(
5374 klass=self.__class__,
5375 decode_path=decode_path,
5379 raise NotEnoughData(
5380 "encoded length is longer than data",
5381 klass=self.__class__,
5382 decode_path=decode_path,
5385 tlvlen = tlen + llen + l
5386 v, tail = tlv[:tlvlen], v[l:]
5387 obj = self.__class__(
5388 value=None if evgen_mode else v.tobytes(),
5390 optional=self.optional,
5391 _decoded=(offset, 0, tlvlen),
5393 obj.tag = t.tobytes()
5394 yield decode_path, obj, tail
5397 return pp_console_row(next(self.pps()))
5399 def pps(self, decode_path=()):
5403 elif value.__class__ == binary_type:
5409 asn1_type_name=self.asn1_type_name,
5410 obj_name=self.__class__.__name__,
5411 decode_path=decode_path,
5413 blob=self._value if self._value.__class__ == binary_type else None,
5414 optional=self.optional,
5415 default=self == self.default,
5416 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5417 expl=None if self._expl is None else tag_decode(self._expl),
5422 expl_offset=self.expl_offset if self.expled else None,
5423 expl_tlen=self.expl_tlen if self.expled else None,
5424 expl_llen=self.expl_llen if self.expled else None,
5425 expl_vlen=self.expl_vlen if self.expled else None,
5426 expl_lenindef=self.expl_lenindef,
5427 lenindef=self.lenindef,
5430 defined_by, defined = self.defined or (None, None)
5431 if defined_by is not None:
5433 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5435 for pp in self.pps_lenindef(decode_path):
5439 ########################################################################
5440 # ASN.1 constructed types
5441 ########################################################################
5443 def get_def_by_path(defines_by_path, sub_decode_path):
5444 """Get define by decode path
5446 for path, define in defines_by_path:
5447 if len(path) != len(sub_decode_path):
5449 for p1, p2 in zip(path, sub_decode_path):
5450 if (not p1 is any) and (p1 != p2):
5456 def abs_decode_path(decode_path, rel_path):
5457 """Create an absolute decode path from current and relative ones
5459 :param decode_path: current decode path, starting point. Tuple of strings
5460 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5461 If first tuple's element is "/", then treat it as
5462 an absolute path, ignoring ``decode_path`` as
5463 starting point. Also this tuple can contain ".."
5464 elements, stripping the leading element from
5467 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5468 ("foo", "bar", "baz", "whatever")
5469 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5471 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5474 if rel_path[0] == "/":
5476 if rel_path[0] == "..":
5477 return abs_decode_path(decode_path[:-1], rel_path[1:])
5478 return decode_path + rel_path
5481 SequenceState = namedtuple(
5483 BasicState._fields + ("specs", "value",),
5488 class Sequence(Obj):
5489 """``SEQUENCE`` structure type
5491 You have to make specification of sequence::
5493 class Extension(Sequence):
5495 ("extnID", ObjectIdentifier()),
5496 ("critical", Boolean(default=False)),
5497 ("extnValue", OctetString()),
5500 Then, you can work with it as with dictionary.
5502 >>> ext = Extension()
5503 >>> Extension().specs
5505 ('extnID', OBJECT IDENTIFIER),
5506 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5507 ('extnValue', OCTET STRING),
5509 >>> ext["extnID"] = "1.2.3"
5510 Traceback (most recent call last):
5511 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5512 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5514 You can determine if sequence is ready to be encoded:
5519 Traceback (most recent call last):
5520 pyderasn.ObjNotReady: object is not ready: extnValue
5521 >>> ext["extnValue"] = OctetString(b"foobar")
5525 Value you want to assign, must have the same **type** as in
5526 corresponding specification, but it can have different tags,
5527 optional/default attributes -- they will be taken from specification
5530 class TBSCertificate(Sequence):
5532 ("version", Version(expl=tag_ctxc(0), default="v1")),
5535 >>> tbs = TBSCertificate()
5536 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5538 Assign ``None`` to remove value from sequence.
5540 You can set values in Sequence during its initialization:
5542 >>> AlgorithmIdentifier((
5543 ("algorithm", ObjectIdentifier("1.2.3")),
5544 ("parameters", Any(Null()))
5546 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5548 You can determine if value exists/set in the sequence and take its value:
5550 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5553 OBJECT IDENTIFIER 1.2.3
5555 But pay attention that if value has default, then it won't be (not
5556 in) in the sequence (because ``DEFAULT`` must not be encoded in
5557 DER), but you can read its value:
5559 >>> "critical" in ext, ext["critical"]
5560 (False, BOOLEAN False)
5561 >>> ext["critical"] = Boolean(True)
5562 >>> "critical" in ext, ext["critical"]
5563 (True, BOOLEAN True)
5565 All defaulted values are always optional.
5567 .. _allow_default_values_ctx:
5569 DER prohibits default value encoding and will raise an error if
5570 default value is unexpectedly met during decode.
5571 If :ref:`bered <bered_ctx>` context option is set, then no error
5572 will be raised, but ``bered`` attribute set. You can disable strict
5573 defaulted values existence validation by setting
5574 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5578 Check for default value existence is not performed in
5579 ``evgen_mode``, because previously decoded values are not stored
5580 in memory, to be able to compare them.
5582 Two sequences are equal if they have equal specification (schema),
5583 implicit/explicit tagging and the same values.
5585 __slots__ = ("specs",)
5586 tag_default = tag_encode(form=TagFormConstructed, num=16)
5587 asn1_type_name = "SEQUENCE"
5599 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5601 schema = getattr(self, "schema", ())
5603 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
5606 if value is not None:
5607 if issubclass(value.__class__, Sequence):
5608 self._value = value._value
5609 elif hasattr(value, "__iter__"):
5610 for seq_key, seq_value in value:
5611 self[seq_key] = seq_value
5613 raise InvalidValueType((Sequence,))
5614 if default is not None:
5615 if not issubclass(default.__class__, Sequence):
5616 raise InvalidValueType((Sequence,))
5617 default_value = default._value
5618 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5619 default_obj.specs = self.specs
5620 default_obj._value = default_value
5621 self.default = default_obj
5623 self._value = copy(default_obj._value)
5627 for name, spec in iteritems(self.specs):
5628 value = self._value.get(name)
5639 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5641 return any(value.bered for value in itervalues(self._value))
5643 def __getstate__(self):
5644 return SequenceState(
5658 {k: copy(v) for k, v in iteritems(self._value)},
5661 def __setstate__(self, state):
5662 super(Sequence, self).__setstate__(state)
5663 self.specs = state.specs
5664 self._value = state.value
5666 def __eq__(self, their):
5667 if not isinstance(their, self.__class__):
5670 self.specs == their.specs and
5671 self.tag == their.tag and
5672 self._expl == their._expl and
5673 self._value == their._value
5684 return self.__class__(
5687 impl=self.tag if impl is None else impl,
5688 expl=self._expl if expl is None else expl,
5689 default=self.default if default is None else default,
5690 optional=self.optional if optional is None else optional,
5693 def __contains__(self, key):
5694 return key in self._value
5696 def __setitem__(self, key, value):
5697 spec = self.specs.get(key)
5699 raise ObjUnknown(key)
5701 self._value.pop(key, None)
5703 if not isinstance(value, spec.__class__):
5704 raise InvalidValueType((spec.__class__,))
5705 value = spec(value=value)
5706 if spec.default is not None and value == spec.default:
5707 self._value.pop(key, None)
5709 self._value[key] = value
5711 def __getitem__(self, key):
5712 value = self._value.get(key)
5713 if value is not None:
5715 spec = self.specs.get(key)
5717 raise ObjUnknown(key)
5718 if spec.default is not None:
5722 def _values_for_encoding(self):
5723 for name, spec in iteritems(self.specs):
5724 value = self._value.get(name)
5728 raise ObjNotReady(name)
5732 v = b"".join(v.encode() for v in self._values_for_encoding())
5733 return b"".join((self.tag, len_encode(len(v)), v))
5735 def _encode_cer(self, writer):
5736 write_full(writer, self.tag + LENINDEF)
5737 for v in self._values_for_encoding():
5738 v.encode_cer(writer)
5739 write_full(writer, EOC)
5741 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5743 t, tlen, lv = tag_strip(tlv)
5744 except DecodeError as err:
5745 raise err.__class__(
5747 klass=self.__class__,
5748 decode_path=decode_path,
5753 klass=self.__class__,
5754 decode_path=decode_path,
5757 if tag_only: # pragma: no cover
5761 ctx_bered = ctx.get("bered", False)
5763 l, llen, v = len_decode(lv)
5764 except LenIndefForm as err:
5766 raise err.__class__(
5768 klass=self.__class__,
5769 decode_path=decode_path,
5772 l, llen, v = 0, 1, lv[1:]
5774 except DecodeError as err:
5775 raise err.__class__(
5777 klass=self.__class__,
5778 decode_path=decode_path,
5782 raise NotEnoughData(
5783 "encoded length is longer than data",
5784 klass=self.__class__,
5785 decode_path=decode_path,
5789 v, tail = v[:l], v[l:]
5791 sub_offset = offset + tlen + llen
5794 ctx_allow_default_values = ctx.get("allow_default_values", False)
5795 for name, spec in iteritems(self.specs):
5796 if spec.optional and (
5797 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5801 sub_decode_path = decode_path + (name,)
5804 for _decode_path, value, v_tail in spec.decode_evgen(
5808 decode_path=sub_decode_path,
5810 _ctx_immutable=False,
5812 yield _decode_path, value, v_tail
5814 _, value, v_tail = next(spec.decode_evgen(
5818 decode_path=sub_decode_path,
5820 _ctx_immutable=False,
5823 except TagMismatch as err:
5824 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5828 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5829 if not evgen_mode and defined is not None:
5830 defined_by, defined_spec = defined
5831 if issubclass(value.__class__, SequenceOf):
5832 for i, _value in enumerate(value):
5833 sub_sub_decode_path = sub_decode_path + (
5835 DecodePathDefBy(defined_by),
5837 defined_value, defined_tail = defined_spec.decode(
5838 memoryview(bytes(_value)),
5840 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5841 if value.expled else (value.tlen + value.llen)
5844 decode_path=sub_sub_decode_path,
5846 _ctx_immutable=False,
5848 if len(defined_tail) > 0:
5851 klass=self.__class__,
5852 decode_path=sub_sub_decode_path,
5855 _value.defined = (defined_by, defined_value)
5857 defined_value, defined_tail = defined_spec.decode(
5858 memoryview(bytes(value)),
5860 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5861 if value.expled else (value.tlen + value.llen)
5864 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5866 _ctx_immutable=False,
5868 if len(defined_tail) > 0:
5871 klass=self.__class__,
5872 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5875 value.defined = (defined_by, defined_value)
5877 value_len = value.fulllen
5879 sub_offset += value_len
5882 if spec.default is not None and value == spec.default:
5883 # This will not work in evgen_mode
5884 if ctx_bered or ctx_allow_default_values:
5888 "DEFAULT value met",
5889 klass=self.__class__,
5890 decode_path=sub_decode_path,
5893 values[name] = value
5894 spec_defines = getattr(spec, "defines", ())
5895 if len(spec_defines) == 0:
5896 defines_by_path = ctx.get("defines_by_path", ())
5897 if len(defines_by_path) > 0:
5898 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5899 if spec_defines is not None and len(spec_defines) > 0:
5900 for rel_path, schema in spec_defines:
5901 defined = schema.get(value, None)
5902 if defined is not None:
5903 ctx.setdefault("_defines", []).append((
5904 abs_decode_path(sub_decode_path[:-1], rel_path),
5908 if v[:EOC_LEN].tobytes() != EOC:
5911 klass=self.__class__,
5912 decode_path=decode_path,
5920 klass=self.__class__,
5921 decode_path=decode_path,
5924 obj = self.__class__(
5928 default=self.default,
5929 optional=self.optional,
5930 _decoded=(offset, llen, vlen),
5933 obj.lenindef = lenindef
5934 obj.ber_encoded = ber_encoded
5935 yield decode_path, obj, tail
5938 value = pp_console_row(next(self.pps()))
5940 for name in self.specs:
5941 _value = self._value.get(name)
5944 cols.append("%s: %s" % (name, repr(_value)))
5945 return "%s[%s]" % (value, "; ".join(cols))
5947 def pps(self, decode_path=()):
5950 asn1_type_name=self.asn1_type_name,
5951 obj_name=self.__class__.__name__,
5952 decode_path=decode_path,
5953 optional=self.optional,
5954 default=self == self.default,
5955 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5956 expl=None if self._expl is None else tag_decode(self._expl),
5961 expl_offset=self.expl_offset if self.expled else None,
5962 expl_tlen=self.expl_tlen if self.expled else None,
5963 expl_llen=self.expl_llen if self.expled else None,
5964 expl_vlen=self.expl_vlen if self.expled else None,
5965 expl_lenindef=self.expl_lenindef,
5966 lenindef=self.lenindef,
5967 ber_encoded=self.ber_encoded,
5970 for name in self.specs:
5971 value = self._value.get(name)
5974 yield value.pps(decode_path=decode_path + (name,))
5975 for pp in self.pps_lenindef(decode_path):
5979 class Set(Sequence):
5980 """``SET`` structure type
5982 Its usage is identical to :py:class:`pyderasn.Sequence`.
5984 .. _allow_unordered_set_ctx:
5986 DER prohibits unordered values encoding and will raise an error
5987 during decode. If :ref:`bered <bered_ctx>` context option is set,
5988 then no error will occur. Also you can disable strict values
5989 ordering check by setting ``"allow_unordered_set": True``
5990 :ref:`context <ctx>` option.
5993 tag_default = tag_encode(form=TagFormConstructed, num=17)
5994 asn1_type_name = "SET"
5997 v = b"".join(value.encode() for value in sorted(
5998 self._values_for_encoding(),
5999 key=attrgetter("tag_order"),
6001 return b"".join((self.tag, len_encode(len(v)), v))
6003 def _encode_cer(self, writer):
6004 write_full(writer, self.tag + LENINDEF)
6006 self._values_for_encoding(),
6007 key=attrgetter("tag_order_cer"),
6009 v.encode_cer(writer)
6010 write_full(writer, EOC)
6012 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
6014 t, tlen, lv = tag_strip(tlv)
6015 except DecodeError as err:
6016 raise err.__class__(
6018 klass=self.__class__,
6019 decode_path=decode_path,
6024 klass=self.__class__,
6025 decode_path=decode_path,
6032 ctx_bered = ctx.get("bered", False)
6034 l, llen, v = len_decode(lv)
6035 except LenIndefForm as err:
6037 raise err.__class__(
6039 klass=self.__class__,
6040 decode_path=decode_path,
6043 l, llen, v = 0, 1, lv[1:]
6045 except DecodeError as err:
6046 raise err.__class__(
6048 klass=self.__class__,
6049 decode_path=decode_path,
6053 raise NotEnoughData(
6054 "encoded length is longer than data",
6055 klass=self.__class__,
6059 v, tail = v[:l], v[l:]
6061 sub_offset = offset + tlen + llen
6064 ctx_allow_default_values = ctx.get("allow_default_values", False)
6065 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6066 tag_order_prev = (0, 0)
6067 _specs_items = copy(self.specs)
6070 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6072 for name, spec in iteritems(_specs_items):
6073 sub_decode_path = decode_path + (name,)
6079 decode_path=sub_decode_path,
6082 _ctx_immutable=False,
6089 klass=self.__class__,
6090 decode_path=decode_path,
6094 for _decode_path, value, v_tail in spec.decode_evgen(
6098 decode_path=sub_decode_path,
6100 _ctx_immutable=False,
6102 yield _decode_path, value, v_tail
6104 _, value, v_tail = next(spec.decode_evgen(
6108 decode_path=sub_decode_path,
6110 _ctx_immutable=False,
6113 value_tag_order = value.tag_order
6114 value_len = value.fulllen
6115 if tag_order_prev >= value_tag_order:
6116 if ctx_bered or ctx_allow_unordered_set:
6120 "unordered " + self.asn1_type_name,
6121 klass=self.__class__,
6122 decode_path=sub_decode_path,
6125 if spec.default is None or value != spec.default:
6127 elif ctx_bered or ctx_allow_default_values:
6131 "DEFAULT value met",
6132 klass=self.__class__,
6133 decode_path=sub_decode_path,
6136 values[name] = value
6137 del _specs_items[name]
6138 tag_order_prev = value_tag_order
6139 sub_offset += value_len
6143 obj = self.__class__(
6147 default=self.default,
6148 optional=self.optional,
6149 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6152 if v[:EOC_LEN].tobytes() != EOC:
6155 klass=self.__class__,
6156 decode_path=decode_path,
6161 for name, spec in iteritems(self.specs):
6162 if name not in values and not spec.optional:
6164 "%s value is not ready" % name,
6165 klass=self.__class__,
6166 decode_path=decode_path,
6171 obj.ber_encoded = ber_encoded
6172 yield decode_path, obj, tail
6175 SequenceOfState = namedtuple(
6177 BasicState._fields + ("spec", "value", "bound_min", "bound_max"),
6182 class SequenceOf(Obj):
6183 """``SEQUENCE OF`` sequence type
6185 For that kind of type you must specify the object it will carry on
6186 (bounds are for example here, not required)::
6188 class Ints(SequenceOf):
6193 >>> ints.append(Integer(123))
6194 >>> ints.append(Integer(234))
6196 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
6197 >>> [int(i) for i in ints]
6199 >>> ints.append(Integer(345))
6200 Traceback (most recent call last):
6201 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
6204 >>> ints[1] = Integer(345)
6206 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
6208 Also you can initialize sequence with preinitialized values:
6210 >>> ints = Ints([Integer(123), Integer(234)])
6212 __slots__ = ("spec", "_bound_min", "_bound_max")
6213 tag_default = tag_encode(form=TagFormConstructed, num=16)
6214 asn1_type_name = "SEQUENCE OF"
6227 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
6229 schema = getattr(self, "schema", None)
6231 raise ValueError("schema must be specified")
6233 self._bound_min, self._bound_max = getattr(
6237 ) if bounds is None else bounds
6239 if value is not None:
6240 self._value = self._value_sanitize(value)
6241 if default is not None:
6242 default_value = self._value_sanitize(default)
6243 default_obj = self.__class__(
6248 default_obj._value = default_value
6249 self.default = default_obj
6251 self._value = copy(default_obj._value)
6253 def _value_sanitize(self, value):
6254 if issubclass(value.__class__, SequenceOf):
6255 value = value._value
6256 elif hasattr(value, "__iter__"):
6259 raise InvalidValueType((self.__class__, iter))
6260 if not self._bound_min <= len(value) <= self._bound_max:
6261 raise BoundsError(self._bound_min, len(value), self._bound_max)
6263 if not isinstance(v, self.spec.__class__):
6264 raise InvalidValueType((self.spec.__class__,))
6269 return all(v.ready for v in self._value)
6273 if self.expl_lenindef or self.lenindef or self.ber_encoded:
6275 return any(v.bered for v in self._value)
6277 def __getstate__(self):
6278 return SequenceOfState(
6292 [copy(v) for v in self._value],
6297 def __setstate__(self, state):
6298 super(SequenceOf, self).__setstate__(state)
6299 self.spec = state.spec
6300 self._value = state.value
6301 self._bound_min = state.bound_min
6302 self._bound_max = state.bound_max
6304 def __eq__(self, their):
6305 if isinstance(their, self.__class__):
6307 self.spec == their.spec and
6308 self.tag == their.tag and
6309 self._expl == their._expl and
6310 self._value == their._value
6312 if hasattr(their, "__iter__"):
6313 return self._value == list(their)
6325 return self.__class__(
6329 (self._bound_min, self._bound_max)
6330 if bounds is None else bounds
6332 impl=self.tag if impl is None else impl,
6333 expl=self._expl if expl is None else expl,
6334 default=self.default if default is None else default,
6335 optional=self.optional if optional is None else optional,
6338 def __contains__(self, key):
6339 return key in self._value
6341 def append(self, value):
6342 if not isinstance(value, self.spec.__class__):
6343 raise InvalidValueType((self.spec.__class__,))
6344 if len(self._value) + 1 > self._bound_max:
6347 len(self._value) + 1,
6350 self._value.append(value)
6353 self._assert_ready()
6354 return iter(self._value)
6357 self._assert_ready()
6358 return len(self._value)
6360 def __setitem__(self, key, value):
6361 if not isinstance(value, self.spec.__class__):
6362 raise InvalidValueType((self.spec.__class__,))
6363 self._value[key] = self.spec(value=value)
6365 def __getitem__(self, key):
6366 return self._value[key]
6368 def _values_for_encoding(self):
6369 return iter(self._value)
6372 v = b"".join(v.encode() for v in self._values_for_encoding())
6373 return b"".join((self.tag, len_encode(len(v)), v))
6375 def _encode_cer(self, writer):
6376 write_full(writer, self.tag + LENINDEF)
6377 for v in self._values_for_encoding():
6378 v.encode_cer(writer)
6379 write_full(writer, EOC)
6389 ordering_check=False,
6392 t, tlen, lv = tag_strip(tlv)
6393 except DecodeError as err:
6394 raise err.__class__(
6396 klass=self.__class__,
6397 decode_path=decode_path,
6402 klass=self.__class__,
6403 decode_path=decode_path,
6410 ctx_bered = ctx.get("bered", False)
6412 l, llen, v = len_decode(lv)
6413 except LenIndefForm as err:
6415 raise err.__class__(
6417 klass=self.__class__,
6418 decode_path=decode_path,
6421 l, llen, v = 0, 1, lv[1:]
6423 except DecodeError as err:
6424 raise err.__class__(
6426 klass=self.__class__,
6427 decode_path=decode_path,
6431 raise NotEnoughData(
6432 "encoded length is longer than data",
6433 klass=self.__class__,
6434 decode_path=decode_path,
6438 v, tail = v[:l], v[l:]
6440 sub_offset = offset + tlen + llen
6443 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6444 value_prev = memoryview(v[:0])
6448 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6450 sub_decode_path = decode_path + (str(_value_count),)
6452 for _decode_path, value, v_tail in spec.decode_evgen(
6456 decode_path=sub_decode_path,
6458 _ctx_immutable=False,
6460 yield _decode_path, value, v_tail
6462 _, value, v_tail = next(spec.decode_evgen(
6466 decode_path=sub_decode_path,
6468 _ctx_immutable=False,
6471 value_len = value.fulllen
6473 if value_prev.tobytes() > v[:value_len].tobytes():
6474 if ctx_bered or ctx_allow_unordered_set:
6478 "unordered " + self.asn1_type_name,
6479 klass=self.__class__,
6480 decode_path=sub_decode_path,
6483 value_prev = v[:value_len]
6486 _value.append(value)
6487 sub_offset += value_len
6490 if evgen_mode and not self._bound_min <= _value_count <= self._bound_max:
6492 msg=str(BoundsError(self._bound_min, _value_count, self._bound_max)),
6493 klass=self.__class__,
6494 decode_path=decode_path,
6498 obj = self.__class__(
6499 value=None if evgen_mode else _value,
6501 bounds=(self._bound_min, self._bound_max),
6504 default=self.default,
6505 optional=self.optional,
6506 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6508 except BoundsError as err:
6511 klass=self.__class__,
6512 decode_path=decode_path,
6516 if v[:EOC_LEN].tobytes() != EOC:
6519 klass=self.__class__,
6520 decode_path=decode_path,
6525 obj.ber_encoded = ber_encoded
6526 yield decode_path, obj, tail
6530 pp_console_row(next(self.pps())),
6531 ", ".join(repr(v) for v in self._value),
6534 def pps(self, decode_path=()):
6537 asn1_type_name=self.asn1_type_name,
6538 obj_name=self.__class__.__name__,
6539 decode_path=decode_path,
6540 optional=self.optional,
6541 default=self == self.default,
6542 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6543 expl=None if self._expl is None else tag_decode(self._expl),
6548 expl_offset=self.expl_offset if self.expled else None,
6549 expl_tlen=self.expl_tlen if self.expled else None,
6550 expl_llen=self.expl_llen if self.expled else None,
6551 expl_vlen=self.expl_vlen if self.expled else None,
6552 expl_lenindef=self.expl_lenindef,
6553 lenindef=self.lenindef,
6554 ber_encoded=self.ber_encoded,
6557 for i, value in enumerate(self._value):
6558 yield value.pps(decode_path=decode_path + (str(i),))
6559 for pp in self.pps_lenindef(decode_path):
6563 class SetOf(SequenceOf):
6564 """``SET OF`` sequence type
6566 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6569 tag_default = tag_encode(form=TagFormConstructed, num=17)
6570 asn1_type_name = "SET OF"
6573 v = b"".join(sorted(v.encode() for v in self._values_for_encoding()))
6574 return b"".join((self.tag, len_encode(len(v)), v))
6576 def _encode_cer(self, writer):
6577 write_full(writer, self.tag + LENINDEF)
6578 for v in sorted(encode_cer(v) for v in self._values_for_encoding()):
6579 write_full(writer, v)
6580 write_full(writer, EOC)
6582 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
6583 return super(SetOf, self)._decode(
6590 ordering_check=True,
6594 def obj_by_path(pypath): # pragma: no cover
6595 """Import object specified as string Python path
6597 Modules must be separated from classes/functions with ``:``.
6599 >>> obj_by_path("foo.bar:Baz")
6600 <class 'foo.bar.Baz'>
6601 >>> obj_by_path("foo.bar:Baz.boo")
6602 <classmethod 'foo.bar.Baz.boo'>
6604 mod, objs = pypath.rsplit(":", 1)
6605 from importlib import import_module
6606 obj = import_module(mod)
6607 for obj_name in objs.split("."):
6608 obj = getattr(obj, obj_name)
6612 def generic_decoder(): # pragma: no cover
6613 # All of this below is a big hack with self references
6614 choice = PrimitiveTypes()
6615 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6616 choice.specs["SetOf"] = SetOf(schema=choice)
6617 for i in six_xrange(31):
6618 choice.specs["SequenceOf%d" % i] = SequenceOf(
6622 choice.specs["Any"] = Any()
6624 # Class name equals to type name, to omit it from output
6625 class SEQUENCEOF(SequenceOf):
6633 with_decode_path=False,
6634 decode_path_only=(),
6636 def _pprint_pps(pps):
6638 if hasattr(pp, "_fields"):
6640 decode_path_only != () and
6641 pp.decode_path[:len(decode_path_only)] != decode_path_only
6644 if pp.asn1_type_name == Choice.asn1_type_name:
6646 pp_kwargs = pp._asdict()
6647 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6648 pp = _pp(**pp_kwargs)
6649 yield pp_console_row(
6654 with_colours=with_colours,
6655 with_decode_path=with_decode_path,
6656 decode_path_len_decrease=len(decode_path_only),
6658 for row in pp_console_blob(
6660 decode_path_len_decrease=len(decode_path_only),
6664 for row in _pprint_pps(pp):
6666 return "\n".join(_pprint_pps(obj.pps()))
6667 return SEQUENCEOF(), pprint_any
6670 def main(): # pragma: no cover
6672 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6673 parser.add_argument(
6677 help="Skip that number of bytes from the beginning",
6679 parser.add_argument(
6681 help="Python paths to dictionary with OIDs, comma separated",
6683 parser.add_argument(
6685 help="Python path to schema definition to use",
6687 parser.add_argument(
6688 "--defines-by-path",
6689 help="Python path to decoder's defines_by_path",
6691 parser.add_argument(
6693 action="store_true",
6694 help="Disallow BER encoding",
6696 parser.add_argument(
6697 "--print-decode-path",
6698 action="store_true",
6699 help="Print decode paths",
6701 parser.add_argument(
6702 "--decode-path-only",
6703 help="Print only specified decode path",
6705 parser.add_argument(
6707 action="store_true",
6708 help="Allow explicit tag out-of-bound",
6710 parser.add_argument(
6712 action="store_true",
6713 help="Turn on event generation mode",
6715 parser.add_argument(
6717 type=argparse.FileType("rb"),
6718 help="Path to BER/CER/DER file you want to decode",
6720 args = parser.parse_args()
6722 args.RAWFile.seek(args.skip)
6723 raw = memoryview(args.RAWFile.read())
6724 args.RAWFile.close()
6726 raw = file_mmaped(args.RAWFile)[args.skip:]
6728 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6729 if args.oids else ()
6732 schema = obj_by_path(args.schema)
6733 from functools import partial
6734 pprinter = partial(pprint, big_blobs=True)
6736 schema, pprinter = generic_decoder()
6738 "bered": not args.nobered,
6739 "allow_expl_oob": args.allow_expl_oob,
6741 if args.defines_by_path is not None:
6742 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6743 from os import environ
6747 with_colours=environ.get("NO_COLOR") is None,
6748 with_decode_path=args.print_decode_path,
6750 () if args.decode_path_only is None else
6751 tuple(args.decode_path_only.split(":"))
6755 for decode_path, obj, tail in schema().decode_evgen(raw, ctx=ctx):
6756 print(pprinter(obj, decode_path=decode_path))
6758 obj, tail = schema().decode(raw, ctx=ctx)
6759 print(pprinter(obj))
6761 print("\nTrailing data: %s" % hexenc(tail))
6764 if __name__ == "__main__":