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):
862 "TagClassApplication",
866 "TagFormConstructed",
877 TagClassUniversal = 0
878 TagClassApplication = 1 << 6
879 TagClassContext = 1 << 7
880 TagClassPrivate = 1 << 6 | 1 << 7
882 TagFormConstructed = 1 << 5
885 TagClassApplication: "APPLICATION ",
886 TagClassPrivate: "PRIVATE ",
887 TagClassUniversal: "UNIV ",
891 LENINDEF = b"\x80" # length indefinite mark
892 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
893 NAMEDTUPLE_KWARGS = {} if version_info < (3, 6) else {"module": __name__}
894 SET01 = frozenset("01")
895 DECIMALS = frozenset(digits)
897 NEXT_ATTR_NAME = "next" if PY2 else "__next__"
901 """Make mmap-ed memoryview for reading from file
903 :param fd: file object
904 :returns: memoryview over read-only mmap-ing of the whole file
906 return memoryview(mmap(fd.fileno(), 0, prot=PROT_READ))
909 if not set(value) <= DECIMALS:
910 raise ValueError("non-pure integer")
913 def fractions2float(fractions_raw):
914 pureint(fractions_raw)
915 return float("0." + fractions_raw)
918 def get_def_by_path(defines_by_path, sub_decode_path):
919 """Get define by decode path
921 for path, define in defines_by_path:
922 if len(path) != len(sub_decode_path):
924 for p1, p2 in zip(path, sub_decode_path):
925 if (not p1 is any) and (p1 != p2):
931 ########################################################################
933 ########################################################################
935 class ASN1Error(ValueError):
939 class DecodeError(ASN1Error):
940 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
942 :param str msg: reason of decode failing
943 :param klass: optional exact DecodeError inherited class (like
944 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
945 :py:exc:`InvalidLength`)
946 :param decode_path: tuple of strings. It contains human
947 readable names of the fields through which
948 decoding process has passed
949 :param int offset: binary offset where failure happened
951 super(DecodeError, self).__init__()
954 self.decode_path = decode_path
960 "" if self.klass is None else self.klass.__name__,
962 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
963 if len(self.decode_path) > 0 else ""
965 ("(at %d)" % self.offset) if self.offset > 0 else "",
971 return "%s(%s)" % (self.__class__.__name__, self)
974 class NotEnoughData(DecodeError):
978 class ExceedingData(ASN1Error):
979 def __init__(self, nbytes):
980 super(ExceedingData, self).__init__()
984 return "%d trailing bytes" % self.nbytes
987 return "%s(%s)" % (self.__class__.__name__, self)
990 class LenIndefForm(DecodeError):
994 class TagMismatch(DecodeError):
998 class InvalidLength(DecodeError):
1002 class InvalidOID(DecodeError):
1006 class ObjUnknown(ASN1Error):
1007 def __init__(self, name):
1008 super(ObjUnknown, self).__init__()
1012 return "object is unknown: %s" % self.name
1015 return "%s(%s)" % (self.__class__.__name__, self)
1018 class ObjNotReady(ASN1Error):
1019 def __init__(self, name):
1020 super(ObjNotReady, self).__init__()
1024 return "object is not ready: %s" % self.name
1027 return "%s(%s)" % (self.__class__.__name__, self)
1030 class InvalidValueType(ASN1Error):
1031 def __init__(self, expected_types):
1032 super(InvalidValueType, self).__init__()
1033 self.expected_types = expected_types
1036 return "invalid value type, expected: %s" % ", ".join(
1037 [repr(t) for t in self.expected_types]
1041 return "%s(%s)" % (self.__class__.__name__, self)
1044 class BoundsError(ASN1Error):
1045 def __init__(self, bound_min, value, bound_max):
1046 super(BoundsError, self).__init__()
1047 self.bound_min = bound_min
1049 self.bound_max = bound_max
1052 return "unsatisfied bounds: %s <= %s <= %s" % (
1059 return "%s(%s)" % (self.__class__.__name__, self)
1062 ########################################################################
1064 ########################################################################
1066 _hexdecoder = getdecoder("hex")
1067 _hexencoder = getencoder("hex")
1071 """Binary data to hexadecimal string convert
1073 return _hexdecoder(data)[0]
1077 """Hexadecimal string to binary data convert
1079 return _hexencoder(data)[0].decode("ascii")
1082 def int_bytes_len(num, byte_len=8):
1085 return int(ceil(float(num.bit_length()) / byte_len))
1088 def zero_ended_encode(num):
1089 octets = bytearray(int_bytes_len(num, 7))
1091 octets[i] = num & 0x7F
1095 octets[i] = 0x80 | (num & 0x7F)
1098 return bytes(octets)
1101 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
1102 """Encode tag to binary form
1104 :param int num: tag's number
1105 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
1106 :py:data:`pyderasn.TagClassContext`,
1107 :py:data:`pyderasn.TagClassApplication`,
1108 :py:data:`pyderasn.TagClassPrivate`)
1109 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
1110 :py:data:`pyderasn.TagFormConstructed`)
1114 return int2byte(klass | form | num)
1115 # [XX|X|11111][1.......][1.......] ... [0.......]
1116 return int2byte(klass | form | 31) + zero_ended_encode(num)
1119 def tag_decode(tag):
1120 """Decode tag from binary form
1124 No validation is performed, assuming that it has already passed.
1126 It returns tuple with three integers, as
1127 :py:func:`pyderasn.tag_encode` accepts.
1129 first_octet = byte2int(tag)
1130 klass = first_octet & 0xC0
1131 form = first_octet & 0x20
1132 if first_octet & 0x1F < 0x1F:
1133 return (klass, form, first_octet & 0x1F)
1135 for octet in iterbytes(tag[1:]):
1138 return (klass, form, num)
1142 """Create CONTEXT PRIMITIVE tag
1144 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
1148 """Create CONTEXT CONSTRUCTED tag
1150 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
1153 def tag_strip(data):
1154 """Take off tag from the data
1156 :returns: (encoded tag, tag length, remaining data)
1159 raise NotEnoughData("no data at all")
1160 if byte2int(data) & 0x1F < 31:
1161 return data[:1], 1, data[1:]
1166 raise DecodeError("unfinished tag")
1167 if indexbytes(data, i) & 0x80 == 0:
1170 return data[:i], i, data[i:]
1176 octets = bytearray(int_bytes_len(l) + 1)
1177 octets[0] = 0x80 | (len(octets) - 1)
1178 for i in six_xrange(len(octets) - 1, 0, -1):
1179 octets[i] = l & 0xFF
1181 return bytes(octets)
1184 def len_decode(data):
1187 :returns: (decoded length, length's length, remaining data)
1188 :raises LenIndefForm: if indefinite form encoding is met
1191 raise NotEnoughData("no data at all")
1192 first_octet = byte2int(data)
1193 if first_octet & 0x80 == 0:
1194 return first_octet, 1, data[1:]
1195 octets_num = first_octet & 0x7F
1196 if octets_num + 1 > len(data):
1197 raise NotEnoughData("encoded length is longer than data")
1199 raise LenIndefForm()
1200 if byte2int(data[1:]) == 0:
1201 raise DecodeError("leading zeros")
1203 for v in iterbytes(data[1:1 + octets_num]):
1206 raise DecodeError("long form instead of short one")
1207 return l, 1 + octets_num, data[1 + octets_num:]
1210 LEN1K = len_encode(1000)
1213 def write_full(writer, data):
1214 """Fully write provided data
1216 BytesIO does not guarantee that the whole data will be written at once.
1218 data = memoryview(data)
1220 while written != len(data):
1221 n = writer(data[written:])
1223 raise ValueError("can not write to buf")
1227 ########################################################################
1229 ########################################################################
1231 class AutoAddSlots(type):
1232 def __new__(cls, name, bases, _dict):
1233 _dict["__slots__"] = _dict.get("__slots__", ())
1234 return type.__new__(cls, name, bases, _dict)
1237 BasicState = namedtuple("BasicState", (
1250 ), **NAMEDTUPLE_KWARGS)
1253 @add_metaclass(AutoAddSlots)
1255 """Common ASN.1 object class
1257 All ASN.1 types are inherited from it. It has metaclass that
1258 automatically adds ``__slots__`` to all inherited classes.
1283 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1284 self._expl = getattr(self, "expl", None) if expl is None else expl
1285 if self.tag != self.tag_default and self._expl is not None:
1286 raise ValueError("implicit and explicit tags can not be set simultaneously")
1287 if self.tag is None:
1288 self._tag_order = None
1290 tag_class, _, tag_num = tag_decode(
1291 self.tag if self._expl is None else self._expl
1293 self._tag_order = (tag_class, tag_num)
1294 if default is not None:
1296 self.optional = optional
1297 self.offset, self.llen, self.vlen = _decoded
1299 self.expl_lenindef = False
1300 self.lenindef = False
1301 self.ber_encoded = False
1304 def ready(self): # pragma: no cover
1305 """Is object ready to be encoded?
1307 raise NotImplementedError()
1309 def _assert_ready(self):
1311 raise ObjNotReady(self.__class__.__name__)
1315 """Is either object or any elements inside is BER encoded?
1317 return self.expl_lenindef or self.lenindef or self.ber_encoded
1321 """Is object decoded?
1323 return (self.llen + self.vlen) > 0
1325 def __getstate__(self): # pragma: no cover
1326 """Used for making safe to be mutable pickleable copies
1328 raise NotImplementedError()
1330 def __setstate__(self, state):
1331 if state.version != __version__:
1332 raise ValueError("data is pickled by different PyDERASN version")
1333 self.tag = state.tag
1334 self._tag_order = state.tag_order
1335 self._expl = state.expl
1336 self.default = state.default
1337 self.optional = state.optional
1338 self.offset = state.offset
1339 self.llen = state.llen
1340 self.vlen = state.vlen
1341 self.expl_lenindef = state.expl_lenindef
1342 self.lenindef = state.lenindef
1343 self.ber_encoded = state.ber_encoded
1346 def tag_order(self):
1347 """Tag's (class, number) used for DER/CER sorting
1349 return self._tag_order
1352 def tag_order_cer(self):
1353 return self.tag_order
1357 """See :ref:`decoding`
1359 return len(self.tag)
1363 """See :ref:`decoding`
1365 return self.tlen + self.llen + self.vlen
1367 def __str__(self): # pragma: no cover
1368 return self.__bytes__() if PY2 else self.__unicode__()
1370 def __ne__(self, their):
1371 return not(self == their)
1373 def __gt__(self, their): # pragma: no cover
1374 return not(self < their)
1376 def __le__(self, their): # pragma: no cover
1377 return (self == their) or (self < their)
1379 def __ge__(self, their): # pragma: no cover
1380 return (self == their) or (self > their)
1382 def _encode(self): # pragma: no cover
1383 raise NotImplementedError()
1385 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode): # pragma: no cover
1386 yield NotImplemented
1389 """Encode the structure
1391 :returns: DER representation
1393 raw = self._encode()
1394 if self._expl is None:
1396 return b"".join((self._expl, len_encode(len(raw)), raw))
1398 def encode_cer(self, writer):
1399 if self._expl is not None:
1400 write_full(writer, self._expl + LENINDEF)
1401 if getattr(self, "der_forced", False):
1402 write_full(writer, self._encode())
1404 self._encode_cer(writer)
1405 if self._expl is not None:
1406 write_full(writer, EOC)
1408 def _encode_cer(self, writer):
1409 write_full(writer, self._encode())
1411 def hexencode(self):
1412 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1414 return hexenc(self.encode())
1424 _ctx_immutable=True,
1426 result = next(self.decode_evgen(
1438 _, obj, tail = result
1449 _ctx_immutable=True,
1454 :param data: either binary or memoryview
1455 :param int offset: initial data's offset
1456 :param bool leavemm: do we need to leave memoryview of remaining
1457 data as is, or convert it to bytes otherwise
1458 :param ctx: optional :ref:`context <ctx>` governing decoding process
1459 :param tag_only: decode only the tag, without length and contents
1460 (used only in Choice and Set structures, trying to
1461 determine if tag satisfies the schema)
1462 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1464 :returns: (Obj, remaining data)
1466 .. seealso:: :ref:`decoding`
1470 elif _ctx_immutable:
1472 tlv = memoryview(data)
1475 get_def_by_path(ctx.get("evgen_mode_upto", ()), decode_path) is not None
1478 if self._expl is None:
1479 for result in self._decode(
1482 decode_path=decode_path,
1485 evgen_mode=_evgen_mode,
1490 _decode_path, obj, tail = result
1491 if not _decode_path is decode_path:
1495 t, tlen, lv = tag_strip(tlv)
1496 except DecodeError as err:
1497 raise err.__class__(
1499 klass=self.__class__,
1500 decode_path=decode_path,
1505 klass=self.__class__,
1506 decode_path=decode_path,
1510 l, llen, v = len_decode(lv)
1511 except LenIndefForm as err:
1512 if not ctx.get("bered", False):
1513 raise err.__class__(
1515 klass=self.__class__,
1516 decode_path=decode_path,
1520 offset += tlen + llen
1521 for result in self._decode(
1524 decode_path=decode_path,
1527 evgen_mode=_evgen_mode,
1529 if tag_only: # pragma: no cover
1532 _decode_path, obj, tail = result
1533 if not _decode_path is decode_path:
1535 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1536 if eoc_expected.tobytes() != EOC:
1539 klass=self.__class__,
1540 decode_path=decode_path,
1544 obj.expl_lenindef = True
1545 except DecodeError as err:
1546 raise err.__class__(
1548 klass=self.__class__,
1549 decode_path=decode_path,
1554 raise NotEnoughData(
1555 "encoded length is longer than data",
1556 klass=self.__class__,
1557 decode_path=decode_path,
1560 for result in self._decode(
1562 offset=offset + tlen + llen,
1563 decode_path=decode_path,
1566 evgen_mode=_evgen_mode,
1568 if tag_only: # pragma: no cover
1571 _decode_path, obj, tail = result
1572 if not _decode_path is decode_path:
1574 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1576 "explicit tag out-of-bound, longer than data",
1577 klass=self.__class__,
1578 decode_path=decode_path,
1581 yield decode_path, obj, (tail if leavemm else tail.tobytes())
1583 def decod(self, data, offset=0, decode_path=(), ctx=None):
1584 """Decode the data, check that tail is empty
1586 :raises ExceedingData: if tail is not empty
1588 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1589 (decode without tail) that also checks that there is no
1592 obj, tail = self.decode(
1595 decode_path=decode_path,
1600 raise ExceedingData(len(tail))
1603 def hexdecode(self, data, *args, **kwargs):
1604 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1606 return self.decode(hexdec(data), *args, **kwargs)
1608 def hexdecod(self, data, *args, **kwargs):
1609 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1611 return self.decod(hexdec(data), *args, **kwargs)
1615 """See :ref:`decoding`
1617 return self._expl is not None
1621 """See :ref:`decoding`
1626 def expl_tlen(self):
1627 """See :ref:`decoding`
1629 return len(self._expl)
1632 def expl_llen(self):
1633 """See :ref:`decoding`
1635 if self.expl_lenindef:
1637 return len(len_encode(self.tlvlen))
1640 def expl_offset(self):
1641 """See :ref:`decoding`
1643 return self.offset - self.expl_tlen - self.expl_llen
1646 def expl_vlen(self):
1647 """See :ref:`decoding`
1652 def expl_tlvlen(self):
1653 """See :ref:`decoding`
1655 return self.expl_tlen + self.expl_llen + self.expl_vlen
1658 def fulloffset(self):
1659 """See :ref:`decoding`
1661 return self.expl_offset if self.expled else self.offset
1665 """See :ref:`decoding`
1667 return self.expl_tlvlen if self.expled else self.tlvlen
1669 def pps_lenindef(self, decode_path):
1670 if self.lenindef and not (
1671 getattr(self, "defined", None) is not None and
1672 self.defined[1].lenindef
1675 asn1_type_name="EOC",
1677 decode_path=decode_path,
1679 self.offset + self.tlvlen -
1680 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1688 if self.expl_lenindef:
1690 asn1_type_name="EOC",
1691 obj_name="EXPLICIT",
1692 decode_path=decode_path,
1693 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1702 def encode_cer(obj):
1703 """Encode to CER in memory
1706 obj.encode_cer(buf.write)
1707 return buf.getvalue()
1710 class DecodePathDefBy(object):
1711 """DEFINED BY representation inside decode path
1713 __slots__ = ("defined_by",)
1715 def __init__(self, defined_by):
1716 self.defined_by = defined_by
1718 def __ne__(self, their):
1719 return not(self == their)
1721 def __eq__(self, their):
1722 if not isinstance(their, self.__class__):
1724 return self.defined_by == their.defined_by
1727 return "DEFINED BY " + str(self.defined_by)
1730 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1733 ########################################################################
1735 ########################################################################
1737 PP = namedtuple("PP", (
1760 ), **NAMEDTUPLE_KWARGS)
1765 asn1_type_name="unknown",
1782 expl_lenindef=False,
1813 def _colourize(what, colour, with_colours, attrs=("bold",)):
1814 return colored(what, colour, attrs=attrs) if with_colours else what
1817 def colonize_hex(hexed):
1818 """Separate hexadecimal string with colons
1820 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1829 with_decode_path=False,
1830 decode_path_len_decrease=0,
1837 " " if pp.expl_offset is None else
1838 ("-%d" % (pp.offset - pp.expl_offset))
1840 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1842 col = _colourize(col, "red", with_colours, ())
1843 col += _colourize("B", "red", with_colours) if pp.bered else " "
1845 col = "[%d,%d,%4d]%s" % (
1849 LENINDEF_PP_CHAR if pp.lenindef else " "
1851 col = _colourize(col, "green", with_colours, ())
1853 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1854 if decode_path_len > 0:
1855 cols.append(" ." * decode_path_len)
1856 ent = pp.decode_path[-1]
1857 if isinstance(ent, DecodePathDefBy):
1858 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1859 value = str(ent.defined_by)
1862 len(oid_maps) > 0 and
1863 ent.defined_by.asn1_type_name ==
1864 ObjectIdentifier.asn1_type_name
1866 for oid_map in oid_maps:
1867 oid_name = oid_map.get(value)
1868 if oid_name is not None:
1869 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1871 if oid_name is None:
1872 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1874 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1875 if pp.expl is not None:
1876 klass, _, num = pp.expl
1877 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1878 cols.append(_colourize(col, "blue", with_colours))
1879 if pp.impl is not None:
1880 klass, _, num = pp.impl
1881 col = "[%s%d]" % (TagClassReprs[klass], num)
1882 cols.append(_colourize(col, "blue", with_colours))
1883 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1884 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1886 cols.append(_colourize("BER", "red", with_colours))
1887 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1888 if pp.value is not None:
1890 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1892 len(oid_maps) > 0 and
1893 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1895 for oid_map in oid_maps:
1896 oid_name = oid_map.get(value)
1897 if oid_name is not None:
1898 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1900 if pp.asn1_type_name == Integer.asn1_type_name:
1901 hex_repr = hex(int(pp.obj._value))[2:].upper()
1902 if len(hex_repr) % 2 != 0:
1903 hex_repr = "0" + hex_repr
1904 cols.append(_colourize(
1905 "(%s)" % colonize_hex(hex_repr),
1910 if pp.blob.__class__ == binary_type:
1911 cols.append(hexenc(pp.blob))
1912 elif pp.blob.__class__ == tuple:
1913 cols.append(", ".join(pp.blob))
1915 cols.append(_colourize("OPTIONAL", "red", with_colours))
1917 cols.append(_colourize("DEFAULT", "red", with_colours))
1918 if with_decode_path:
1919 cols.append(_colourize(
1920 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1924 return " ".join(cols)
1927 def pp_console_blob(pp, decode_path_len_decrease=0):
1928 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1929 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1930 if decode_path_len > 0:
1931 cols.append(" ." * (decode_path_len + 1))
1932 if pp.blob.__class__ == binary_type:
1933 blob = hexenc(pp.blob).upper()
1934 for i in six_xrange(0, len(blob), 32):
1935 chunk = blob[i:i + 32]
1936 yield " ".join(cols + [colonize_hex(chunk)])
1937 elif pp.blob.__class__ == tuple:
1938 yield " ".join(cols + [", ".join(pp.blob)])
1946 with_decode_path=False,
1947 decode_path_only=(),
1950 """Pretty print object
1952 :param Obj obj: object you want to pretty print
1953 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1954 Its human readable form is printed when OID is met
1955 :param big_blobs: if large binary objects are met (like OctetString
1956 values), do we need to print them too, on separate
1958 :param with_colours: colourize output, if ``termcolor`` library
1960 :param with_decode_path: print decode path
1961 :param decode_path_only: print only that specified decode path
1963 def _pprint_pps(pps):
1965 if hasattr(pp, "_fields"):
1967 decode_path_only != () and
1969 str(p) for p in pp.decode_path[:len(decode_path_only)]
1970 ) != decode_path_only
1974 yield pp_console_row(
1979 with_colours=with_colours,
1980 with_decode_path=with_decode_path,
1981 decode_path_len_decrease=len(decode_path_only),
1983 for row in pp_console_blob(
1985 decode_path_len_decrease=len(decode_path_only),
1989 yield pp_console_row(
1994 with_colours=with_colours,
1995 with_decode_path=with_decode_path,
1996 decode_path_len_decrease=len(decode_path_only),
1999 for row in _pprint_pps(pp):
2001 return "\n".join(_pprint_pps(obj.pps(decode_path)))
2004 ########################################################################
2005 # ASN.1 primitive types
2006 ########################################################################
2008 BooleanState = namedtuple(
2010 BasicState._fields + ("value",),
2016 """``BOOLEAN`` boolean type
2018 >>> b = Boolean(True)
2020 >>> b == Boolean(True)
2026 tag_default = tag_encode(1)
2027 asn1_type_name = "BOOLEAN"
2039 :param value: set the value. Either boolean type, or
2040 :py:class:`pyderasn.Boolean` object
2041 :param bytes impl: override default tag with ``IMPLICIT`` one
2042 :param bytes expl: override default tag with ``EXPLICIT`` one
2043 :param default: set default value. Type same as in ``value``
2044 :param bool optional: is object ``OPTIONAL`` in sequence
2046 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
2047 self._value = None if value is None else self._value_sanitize(value)
2048 if default is not None:
2049 default = self._value_sanitize(default)
2050 self.default = self.__class__(
2056 self._value = default
2058 def _value_sanitize(self, value):
2059 if value.__class__ == bool:
2061 if issubclass(value.__class__, Boolean):
2063 raise InvalidValueType((self.__class__, bool))
2067 return self._value is not None
2069 def __getstate__(self):
2070 return BooleanState(
2086 def __setstate__(self, state):
2087 super(Boolean, self).__setstate__(state)
2088 self._value = state.value
2090 def __nonzero__(self):
2091 self._assert_ready()
2095 self._assert_ready()
2098 def __eq__(self, their):
2099 if their.__class__ == bool:
2100 return self._value == their
2101 if not issubclass(their.__class__, Boolean):
2104 self._value == their._value and
2105 self.tag == their.tag and
2106 self._expl == their._expl
2117 return self.__class__(
2119 impl=self.tag if impl is None else impl,
2120 expl=self._expl if expl is None else expl,
2121 default=self.default if default is None else default,
2122 optional=self.optional if optional is None else optional,
2126 self._assert_ready()
2130 (b"\xFF" if self._value else b"\x00"),
2133 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2135 t, _, lv = tag_strip(tlv)
2136 except DecodeError as err:
2137 raise err.__class__(
2139 klass=self.__class__,
2140 decode_path=decode_path,
2145 klass=self.__class__,
2146 decode_path=decode_path,
2153 l, _, v = len_decode(lv)
2154 except DecodeError as err:
2155 raise err.__class__(
2157 klass=self.__class__,
2158 decode_path=decode_path,
2162 raise InvalidLength(
2163 "Boolean's length must be equal to 1",
2164 klass=self.__class__,
2165 decode_path=decode_path,
2169 raise NotEnoughData(
2170 "encoded length is longer than data",
2171 klass=self.__class__,
2172 decode_path=decode_path,
2175 first_octet = byte2int(v)
2177 if first_octet == 0:
2179 elif first_octet == 0xFF:
2181 elif ctx.get("bered", False):
2186 "unacceptable Boolean value",
2187 klass=self.__class__,
2188 decode_path=decode_path,
2191 obj = self.__class__(
2195 default=self.default,
2196 optional=self.optional,
2197 _decoded=(offset, 1, 1),
2199 obj.ber_encoded = ber_encoded
2200 yield decode_path, obj, v[1:]
2203 return pp_console_row(next(self.pps()))
2205 def pps(self, decode_path=()):
2208 asn1_type_name=self.asn1_type_name,
2209 obj_name=self.__class__.__name__,
2210 decode_path=decode_path,
2211 value=str(self._value) if self.ready else None,
2212 optional=self.optional,
2213 default=self == self.default,
2214 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2215 expl=None if self._expl is None else tag_decode(self._expl),
2220 expl_offset=self.expl_offset if self.expled else None,
2221 expl_tlen=self.expl_tlen if self.expled else None,
2222 expl_llen=self.expl_llen if self.expled else None,
2223 expl_vlen=self.expl_vlen if self.expled else None,
2224 expl_lenindef=self.expl_lenindef,
2225 ber_encoded=self.ber_encoded,
2228 for pp in self.pps_lenindef(decode_path):
2232 IntegerState = namedtuple(
2234 BasicState._fields + ("specs", "value", "bound_min", "bound_max"),
2240 """``INTEGER`` integer type
2242 >>> b = Integer(-123)
2244 >>> b == Integer(-123)
2249 >>> Integer(2, bounds=(1, 3))
2251 >>> Integer(5, bounds=(1, 3))
2252 Traceback (most recent call last):
2253 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2257 class Version(Integer):
2264 >>> v = Version("v1")
2271 {'v3': 2, 'v1': 0, 'v2': 1}
2273 __slots__ = ("specs", "_bound_min", "_bound_max")
2274 tag_default = tag_encode(2)
2275 asn1_type_name = "INTEGER"
2289 :param value: set the value. Either integer type, named value
2290 (if ``schema`` is specified in the class), or
2291 :py:class:`pyderasn.Integer` object
2292 :param bounds: set ``(MIN, MAX)`` value constraint.
2293 (-inf, +inf) by default
2294 :param bytes impl: override default tag with ``IMPLICIT`` one
2295 :param bytes expl: override default tag with ``EXPLICIT`` one
2296 :param default: set default value. Type same as in ``value``
2297 :param bool optional: is object ``OPTIONAL`` in sequence
2299 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2301 specs = getattr(self, "schema", {}) if _specs is None else _specs
2302 self.specs = specs if specs.__class__ == dict else dict(specs)
2303 self._bound_min, self._bound_max = getattr(
2306 (float("-inf"), float("+inf")),
2307 ) if bounds is None else bounds
2308 if value is not None:
2309 self._value = self._value_sanitize(value)
2310 if default is not None:
2311 default = self._value_sanitize(default)
2312 self.default = self.__class__(
2318 if self._value is None:
2319 self._value = default
2321 def _value_sanitize(self, value):
2322 if isinstance(value, integer_types):
2324 elif issubclass(value.__class__, Integer):
2325 value = value._value
2326 elif value.__class__ == str:
2327 value = self.specs.get(value)
2329 raise ObjUnknown("integer value: %s" % value)
2331 raise InvalidValueType((self.__class__, int, str))
2332 if not self._bound_min <= value <= self._bound_max:
2333 raise BoundsError(self._bound_min, value, self._bound_max)
2338 return self._value is not None
2340 def __getstate__(self):
2341 return IntegerState(
2360 def __setstate__(self, state):
2361 super(Integer, self).__setstate__(state)
2362 self.specs = state.specs
2363 self._value = state.value
2364 self._bound_min = state.bound_min
2365 self._bound_max = state.bound_max
2368 self._assert_ready()
2369 return int(self._value)
2372 self._assert_ready()
2375 bytes(self._expl or b"") +
2376 str(self._value).encode("ascii"),
2379 def __eq__(self, their):
2380 if isinstance(their, integer_types):
2381 return self._value == their
2382 if not issubclass(their.__class__, Integer):
2385 self._value == their._value and
2386 self.tag == their.tag and
2387 self._expl == their._expl
2390 def __lt__(self, their):
2391 return self._value < their._value
2395 """Return named representation (if exists) of the value
2397 for name, value in iteritems(self.specs):
2398 if value == self._value:
2411 return self.__class__(
2414 (self._bound_min, self._bound_max)
2415 if bounds is None else bounds
2417 impl=self.tag if impl is None else impl,
2418 expl=self._expl if expl is None else expl,
2419 default=self.default if default is None else default,
2420 optional=self.optional if optional is None else optional,
2425 self._assert_ready()
2429 octets = bytearray([0])
2433 octets = bytearray()
2435 octets.append((value & 0xFF) ^ 0xFF)
2437 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2440 octets = bytearray()
2442 octets.append(value & 0xFF)
2444 if octets[-1] & 0x80 > 0:
2447 octets = bytes(octets)
2449 bytes_len = ceil(value.bit_length() / 8) or 1
2452 octets = value.to_bytes(
2457 except OverflowError:
2461 return b"".join((self.tag, len_encode(len(octets)), octets))
2463 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2465 t, _, lv = tag_strip(tlv)
2466 except DecodeError as err:
2467 raise err.__class__(
2469 klass=self.__class__,
2470 decode_path=decode_path,
2475 klass=self.__class__,
2476 decode_path=decode_path,
2483 l, llen, v = len_decode(lv)
2484 except DecodeError as err:
2485 raise err.__class__(
2487 klass=self.__class__,
2488 decode_path=decode_path,
2492 raise NotEnoughData(
2493 "encoded length is longer than data",
2494 klass=self.__class__,
2495 decode_path=decode_path,
2499 raise NotEnoughData(
2501 klass=self.__class__,
2502 decode_path=decode_path,
2505 v, tail = v[:l], v[l:]
2506 first_octet = byte2int(v)
2508 second_octet = byte2int(v[1:])
2510 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2511 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2514 "non normalized integer",
2515 klass=self.__class__,
2516 decode_path=decode_path,
2521 if first_octet & 0x80 > 0:
2522 octets = bytearray()
2523 for octet in bytearray(v):
2524 octets.append(octet ^ 0xFF)
2525 for octet in octets:
2526 value = (value << 8) | octet
2530 for octet in bytearray(v):
2531 value = (value << 8) | octet
2533 value = int.from_bytes(v, byteorder="big", signed=True)
2535 obj = self.__class__(
2537 bounds=(self._bound_min, self._bound_max),
2540 default=self.default,
2541 optional=self.optional,
2543 _decoded=(offset, llen, l),
2545 except BoundsError as err:
2548 klass=self.__class__,
2549 decode_path=decode_path,
2552 yield decode_path, obj, tail
2555 return pp_console_row(next(self.pps()))
2557 def pps(self, decode_path=()):
2560 asn1_type_name=self.asn1_type_name,
2561 obj_name=self.__class__.__name__,
2562 decode_path=decode_path,
2563 value=(self.named or str(self._value)) if self.ready else None,
2564 optional=self.optional,
2565 default=self == self.default,
2566 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2567 expl=None if self._expl is None else tag_decode(self._expl),
2572 expl_offset=self.expl_offset if self.expled else None,
2573 expl_tlen=self.expl_tlen if self.expled else None,
2574 expl_llen=self.expl_llen if self.expled else None,
2575 expl_vlen=self.expl_vlen if self.expled else None,
2576 expl_lenindef=self.expl_lenindef,
2579 for pp in self.pps_lenindef(decode_path):
2583 BitStringState = namedtuple(
2585 BasicState._fields + ("specs", "value", "tag_constructed", "defined"),
2590 class BitString(Obj):
2591 """``BIT STRING`` bit string type
2593 >>> BitString(b"hello world")
2594 BIT STRING 88 bits 68656c6c6f20776f726c64
2597 >>> b == b"hello world"
2602 >>> BitString("'0A3B5F291CD'H")
2603 BIT STRING 44 bits 0a3b5f291cd0
2604 >>> b = BitString("'010110000000'B")
2605 BIT STRING 12 bits 5800
2608 >>> b[0], b[1], b[2], b[3]
2609 (False, True, False, True)
2613 [False, True, False, True, True, False, False, False, False, False, False, False]
2617 class KeyUsage(BitString):
2619 ("digitalSignature", 0),
2620 ("nonRepudiation", 1),
2621 ("keyEncipherment", 2),
2624 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2625 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2627 ['nonRepudiation', 'keyEncipherment']
2629 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2633 Pay attention that BIT STRING can be encoded both in primitive
2634 and constructed forms. Decoder always checks constructed form tag
2635 additionally to specified primitive one. If BER decoding is
2636 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2637 of DER restrictions.
2639 __slots__ = ("tag_constructed", "specs", "defined")
2640 tag_default = tag_encode(3)
2641 asn1_type_name = "BIT STRING"
2654 :param value: set the value. Either binary type, tuple of named
2655 values (if ``schema`` is specified in the class),
2656 string in ``'XXX...'B`` form, or
2657 :py:class:`pyderasn.BitString` object
2658 :param bytes impl: override default tag with ``IMPLICIT`` one
2659 :param bytes expl: override default tag with ``EXPLICIT`` one
2660 :param default: set default value. Type same as in ``value``
2661 :param bool optional: is object ``OPTIONAL`` in sequence
2663 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2664 specs = getattr(self, "schema", {}) if _specs is None else _specs
2665 self.specs = specs if specs.__class__ == dict else dict(specs)
2666 self._value = None if value is None else self._value_sanitize(value)
2667 if default is not None:
2668 default = self._value_sanitize(default)
2669 self.default = self.__class__(
2675 self._value = default
2677 tag_klass, _, tag_num = tag_decode(self.tag)
2678 self.tag_constructed = tag_encode(
2680 form=TagFormConstructed,
2684 def _bits2octets(self, bits):
2685 if len(self.specs) > 0:
2686 bits = bits.rstrip("0")
2688 bits += "0" * ((8 - (bit_len % 8)) % 8)
2689 octets = bytearray(len(bits) // 8)
2690 for i in six_xrange(len(octets)):
2691 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2692 return bit_len, bytes(octets)
2694 def _value_sanitize(self, value):
2695 if isinstance(value, (string_types, binary_type)):
2697 isinstance(value, string_types) and
2698 value.startswith("'")
2700 if value.endswith("'B"):
2702 if not frozenset(value) <= SET01:
2703 raise ValueError("B's coding contains unacceptable chars")
2704 return self._bits2octets(value)
2705 if value.endswith("'H"):
2709 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2711 if value.__class__ == binary_type:
2712 return (len(value) * 8, value)
2713 raise InvalidValueType((self.__class__, string_types, binary_type))
2714 if value.__class__ == tuple:
2717 isinstance(value[0], integer_types) and
2718 value[1].__class__ == binary_type
2723 bit = self.specs.get(name)
2725 raise ObjUnknown("BitString value: %s" % name)
2728 return self._bits2octets("")
2729 bits = frozenset(bits)
2730 return self._bits2octets("".join(
2731 ("1" if bit in bits else "0")
2732 for bit in six_xrange(max(bits) + 1)
2734 if issubclass(value.__class__, BitString):
2736 raise InvalidValueType((self.__class__, binary_type, string_types))
2740 return self._value is not None
2742 def __getstate__(self):
2743 return BitStringState(
2758 self.tag_constructed,
2762 def __setstate__(self, state):
2763 super(BitString, self).__setstate__(state)
2764 self.specs = state.specs
2765 self._value = state.value
2766 self.tag_constructed = state.tag_constructed
2767 self.defined = state.defined
2770 self._assert_ready()
2771 for i in six_xrange(self._value[0]):
2776 """Returns number of bits in the string
2778 self._assert_ready()
2779 return self._value[0]
2781 def __bytes__(self):
2782 self._assert_ready()
2783 return self._value[1]
2785 def __eq__(self, their):
2786 if their.__class__ == bytes:
2787 return self._value[1] == their
2788 if not issubclass(their.__class__, BitString):
2791 self._value == their._value and
2792 self.tag == their.tag and
2793 self._expl == their._expl
2798 """Named representation (if exists) of the bits
2800 :returns: [str(name), ...]
2802 return [name for name, bit in iteritems(self.specs) if self[bit]]
2812 return self.__class__(
2814 impl=self.tag if impl is None else impl,
2815 expl=self._expl if expl is None else expl,
2816 default=self.default if default is None else default,
2817 optional=self.optional if optional is None else optional,
2821 def __getitem__(self, key):
2822 if key.__class__ == int:
2823 bit_len, octets = self._value
2827 byte2int(memoryview(octets)[key // 8:]) >>
2830 if isinstance(key, string_types):
2831 value = self.specs.get(key)
2833 raise ObjUnknown("BitString value: %s" % key)
2835 raise InvalidValueType((int, str))
2838 self._assert_ready()
2839 bit_len, octets = self._value
2842 len_encode(len(octets) + 1),
2843 int2byte((8 - bit_len % 8) % 8),
2847 def _encode_cer(self, writer):
2848 bit_len, octets = self._value
2849 if len(octets) + 1 <= 1000:
2850 write_full(writer, self._encode())
2852 write_full(writer, self.tag_constructed)
2853 write_full(writer, LENINDEF)
2854 for offset in six_xrange(0, (len(octets) // 999) * 999, 999):
2855 write_full(writer, b"".join((
2856 BitString.tag_default,
2859 octets[offset:offset + 999],
2861 tail = octets[offset+999:]
2863 tail = int2byte((8 - bit_len % 8) % 8) + tail
2864 write_full(writer, b"".join((
2865 BitString.tag_default,
2866 len_encode(len(tail)),
2869 write_full(writer, EOC)
2871 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2873 t, tlen, lv = tag_strip(tlv)
2874 except DecodeError as err:
2875 raise err.__class__(
2877 klass=self.__class__,
2878 decode_path=decode_path,
2882 if tag_only: # pragma: no cover
2886 l, llen, v = len_decode(lv)
2887 except DecodeError as err:
2888 raise err.__class__(
2890 klass=self.__class__,
2891 decode_path=decode_path,
2895 raise NotEnoughData(
2896 "encoded length is longer than data",
2897 klass=self.__class__,
2898 decode_path=decode_path,
2902 raise NotEnoughData(
2904 klass=self.__class__,
2905 decode_path=decode_path,
2908 pad_size = byte2int(v)
2909 if l == 1 and pad_size != 0:
2911 "invalid empty value",
2912 klass=self.__class__,
2913 decode_path=decode_path,
2919 klass=self.__class__,
2920 decode_path=decode_path,
2923 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2926 klass=self.__class__,
2927 decode_path=decode_path,
2930 v, tail = v[:l], v[l:]
2931 bit_len = (len(v) - 1) * 8 - pad_size
2932 obj = self.__class__(
2933 value=None if evgen_mode else (bit_len, v[1:].tobytes()),
2936 default=self.default,
2937 optional=self.optional,
2939 _decoded=(offset, llen, l),
2942 obj._value = (bit_len, None)
2943 yield decode_path, obj, tail
2945 if t != self.tag_constructed:
2947 klass=self.__class__,
2948 decode_path=decode_path,
2951 if not ctx.get("bered", False):
2953 "unallowed BER constructed encoding",
2954 klass=self.__class__,
2955 decode_path=decode_path,
2958 if tag_only: # pragma: no cover
2963 l, llen, v = len_decode(lv)
2964 except LenIndefForm:
2965 llen, l, v = 1, 0, lv[1:]
2967 except DecodeError as err:
2968 raise err.__class__(
2970 klass=self.__class__,
2971 decode_path=decode_path,
2975 raise NotEnoughData(
2976 "encoded length is longer than data",
2977 klass=self.__class__,
2978 decode_path=decode_path,
2981 if not lenindef and l == 0:
2982 raise NotEnoughData(
2984 klass=self.__class__,
2985 decode_path=decode_path,
2989 sub_offset = offset + tlen + llen
2993 if v[:EOC_LEN].tobytes() == EOC:
3000 "chunk out of bounds",
3001 klass=self.__class__,
3002 decode_path=decode_path + (str(len(chunks) - 1),),
3003 offset=chunks[-1].offset,
3005 sub_decode_path = decode_path + (str(len(chunks)),)
3008 for _decode_path, chunk, v_tail in BitString().decode_evgen(
3011 decode_path=sub_decode_path,
3014 _ctx_immutable=False,
3016 yield _decode_path, chunk, v_tail
3018 _, chunk, v_tail = next(BitString().decode_evgen(
3021 decode_path=sub_decode_path,
3024 _ctx_immutable=False,
3029 "expected BitString encoded chunk",
3030 klass=self.__class__,
3031 decode_path=sub_decode_path,
3034 chunks.append(chunk)
3035 sub_offset += chunk.tlvlen
3036 vlen += chunk.tlvlen
3038 if len(chunks) == 0:
3041 klass=self.__class__,
3042 decode_path=decode_path,
3047 for chunk_i, chunk in enumerate(chunks[:-1]):
3048 if chunk.bit_len % 8 != 0:
3050 "BitString chunk is not multiple of 8 bits",
3051 klass=self.__class__,
3052 decode_path=decode_path + (str(chunk_i),),
3053 offset=chunk.offset,
3056 values.append(bytes(chunk))
3057 bit_len += chunk.bit_len
3058 chunk_last = chunks[-1]
3060 values.append(bytes(chunk_last))
3061 bit_len += chunk_last.bit_len
3062 obj = self.__class__(
3063 value=None if evgen_mode else (bit_len, b"".join(values)),
3066 default=self.default,
3067 optional=self.optional,
3069 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3072 obj._value = (bit_len, None)
3073 obj.lenindef = lenindef
3074 obj.ber_encoded = True
3075 yield decode_path, obj, (v[EOC_LEN:] if lenindef else v)
3078 return pp_console_row(next(self.pps()))
3080 def pps(self, decode_path=()):
3084 bit_len, blob = self._value
3085 value = "%d bits" % bit_len
3086 if len(self.specs) > 0 and blob is not None:
3087 blob = tuple(self.named)
3090 asn1_type_name=self.asn1_type_name,
3091 obj_name=self.__class__.__name__,
3092 decode_path=decode_path,
3095 optional=self.optional,
3096 default=self == self.default,
3097 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3098 expl=None if self._expl is None else tag_decode(self._expl),
3103 expl_offset=self.expl_offset if self.expled else None,
3104 expl_tlen=self.expl_tlen if self.expled else None,
3105 expl_llen=self.expl_llen if self.expled else None,
3106 expl_vlen=self.expl_vlen if self.expled else None,
3107 expl_lenindef=self.expl_lenindef,
3108 lenindef=self.lenindef,
3109 ber_encoded=self.ber_encoded,
3112 defined_by, defined = self.defined or (None, None)
3113 if defined_by is not None:
3115 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3117 for pp in self.pps_lenindef(decode_path):
3121 OctetStringState = namedtuple(
3123 BasicState._fields + (
3134 class OctetString(Obj):
3135 """``OCTET STRING`` binary string type
3137 >>> s = OctetString(b"hello world")
3138 OCTET STRING 11 bytes 68656c6c6f20776f726c64
3139 >>> s == OctetString(b"hello world")
3144 >>> OctetString(b"hello", bounds=(4, 4))
3145 Traceback (most recent call last):
3146 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
3147 >>> OctetString(b"hell", bounds=(4, 4))
3148 OCTET STRING 4 bytes 68656c6c
3150 Memoryviews can be used as a values. If memoryview is made on
3151 mmap-ed file, then it does not take storage inside OctetString
3152 itself. In CER encoding mode it will be streamed to the specified
3153 writer, copying 1 KB chunks.
3155 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
3156 tag_default = tag_encode(4)
3157 asn1_type_name = "OCTET STRING"
3158 evgen_mode_skip_value = True
3172 :param value: set the value. Either binary type, or
3173 :py:class:`pyderasn.OctetString` object
3174 :param bounds: set ``(MIN, MAX)`` value size constraint.
3175 (-inf, +inf) by default
3176 :param bytes impl: override default tag with ``IMPLICIT`` one
3177 :param bytes expl: override default tag with ``EXPLICIT`` one
3178 :param default: set default value. Type same as in ``value``
3179 :param bool optional: is object ``OPTIONAL`` in sequence
3181 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
3183 self._bound_min, self._bound_max = getattr(
3187 ) if bounds is None else bounds
3188 if value is not None:
3189 self._value = self._value_sanitize(value)
3190 if default is not None:
3191 default = self._value_sanitize(default)
3192 self.default = self.__class__(
3197 if self._value is None:
3198 self._value = default
3200 tag_klass, _, tag_num = tag_decode(self.tag)
3201 self.tag_constructed = tag_encode(
3203 form=TagFormConstructed,
3207 def _value_sanitize(self, value):
3208 if value.__class__ == binary_type or value.__class__ == memoryview:
3210 elif issubclass(value.__class__, OctetString):
3211 value = value._value
3213 raise InvalidValueType((self.__class__, bytes, memoryview))
3214 if not self._bound_min <= len(value) <= self._bound_max:
3215 raise BoundsError(self._bound_min, len(value), self._bound_max)
3220 return self._value is not None
3222 def __getstate__(self):
3223 return OctetStringState(
3239 self.tag_constructed,
3243 def __setstate__(self, state):
3244 super(OctetString, self).__setstate__(state)
3245 self._value = state.value
3246 self._bound_min = state.bound_min
3247 self._bound_max = state.bound_max
3248 self.tag_constructed = state.tag_constructed
3249 self.defined = state.defined
3251 def __bytes__(self):
3252 self._assert_ready()
3253 return bytes(self._value)
3255 def __eq__(self, their):
3256 if their.__class__ == binary_type:
3257 return self._value == their
3258 if not issubclass(their.__class__, OctetString):
3261 self._value == their._value and
3262 self.tag == their.tag and
3263 self._expl == their._expl
3266 def __lt__(self, their):
3267 return self._value < their._value
3278 return self.__class__(
3281 (self._bound_min, self._bound_max)
3282 if bounds is None else bounds
3284 impl=self.tag if impl is None else impl,
3285 expl=self._expl if expl is None else expl,
3286 default=self.default if default is None else default,
3287 optional=self.optional if optional is None else optional,
3291 self._assert_ready()
3294 len_encode(len(self._value)),
3298 def _encode_cer(self, writer):
3299 octets = self._value
3300 if len(octets) <= 1000:
3301 write_full(writer, self._encode())
3303 write_full(writer, self.tag_constructed)
3304 write_full(writer, LENINDEF)
3305 for offset in six_xrange(0, (len(octets) // 1000) * 1000, 1000):
3306 write_full(writer, b"".join((
3307 OctetString.tag_default,
3309 octets[offset:offset + 1000],
3311 tail = octets[offset+1000:]
3313 write_full(writer, b"".join((
3314 OctetString.tag_default,
3315 len_encode(len(tail)),
3318 write_full(writer, EOC)
3320 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3322 t, tlen, lv = tag_strip(tlv)
3323 except DecodeError as err:
3324 raise err.__class__(
3326 klass=self.__class__,
3327 decode_path=decode_path,
3335 l, llen, v = len_decode(lv)
3336 except DecodeError as err:
3337 raise err.__class__(
3339 klass=self.__class__,
3340 decode_path=decode_path,
3344 raise NotEnoughData(
3345 "encoded length is longer than data",
3346 klass=self.__class__,
3347 decode_path=decode_path,
3350 v, tail = v[:l], v[l:]
3351 if evgen_mode and not self._bound_min <= len(v) <= self._bound_max:
3353 msg=str(BoundsError(self._bound_min, len(v), self._bound_max)),
3354 klass=self.__class__,
3355 decode_path=decode_path,
3359 obj = self.__class__(
3361 None if (evgen_mode and self.evgen_mode_skip_value)
3364 bounds=(self._bound_min, self._bound_max),
3367 default=self.default,
3368 optional=self.optional,
3369 _decoded=(offset, llen, l),
3372 except DecodeError as err:
3375 klass=self.__class__,
3376 decode_path=decode_path,
3379 except BoundsError as err:
3382 klass=self.__class__,
3383 decode_path=decode_path,
3386 yield decode_path, obj, tail
3388 if t != self.tag_constructed:
3390 klass=self.__class__,
3391 decode_path=decode_path,
3394 if not ctx.get("bered", False):
3396 "unallowed BER constructed encoding",
3397 klass=self.__class__,
3398 decode_path=decode_path,
3406 l, llen, v = len_decode(lv)
3407 except LenIndefForm:
3408 llen, l, v = 1, 0, lv[1:]
3410 except DecodeError as err:
3411 raise err.__class__(
3413 klass=self.__class__,
3414 decode_path=decode_path,
3418 raise NotEnoughData(
3419 "encoded length is longer than data",
3420 klass=self.__class__,
3421 decode_path=decode_path,
3426 sub_offset = offset + tlen + llen
3431 if v[:EOC_LEN].tobytes() == EOC:
3438 "chunk out of bounds",
3439 klass=self.__class__,
3440 decode_path=decode_path + (str(len(chunks) - 1),),
3441 offset=chunks[-1].offset,
3445 sub_decode_path = decode_path + (str(chunks_count),)
3446 for _decode_path, chunk, v_tail in OctetString().decode_evgen(
3449 decode_path=sub_decode_path,
3452 _ctx_immutable=False,
3454 yield _decode_path, chunk, v_tail
3455 if not chunk.ber_encoded:
3456 payload_len += chunk.vlen
3459 sub_decode_path = decode_path + (str(len(chunks)),)
3460 _, chunk, v_tail = next(OctetString().decode_evgen(
3463 decode_path=sub_decode_path,
3466 _ctx_immutable=False,
3469 chunks.append(chunk)
3472 "expected OctetString encoded chunk",
3473 klass=self.__class__,
3474 decode_path=sub_decode_path,
3477 sub_offset += chunk.tlvlen
3478 vlen += chunk.tlvlen
3480 if evgen_mode and not self._bound_min <= payload_len <= self._bound_max:
3482 msg=str(BoundsError(self._bound_min, payload_len, self._bound_max)),
3483 klass=self.__class__,
3484 decode_path=decode_path,
3488 obj = self.__class__(
3490 None if evgen_mode else
3491 b"".join(bytes(chunk) for chunk in chunks)
3493 bounds=(self._bound_min, self._bound_max),
3496 default=self.default,
3497 optional=self.optional,
3498 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3501 except DecodeError as err:
3504 klass=self.__class__,
3505 decode_path=decode_path,
3508 except BoundsError as err:
3511 klass=self.__class__,
3512 decode_path=decode_path,
3515 obj.lenindef = lenindef
3516 obj.ber_encoded = True
3517 yield decode_path, obj, (v[EOC_LEN:] if lenindef else v)
3520 return pp_console_row(next(self.pps()))
3522 def pps(self, decode_path=()):
3525 asn1_type_name=self.asn1_type_name,
3526 obj_name=self.__class__.__name__,
3527 decode_path=decode_path,
3528 value=("%d bytes" % len(self._value)) if self.ready else None,
3529 blob=self._value if self.ready else None,
3530 optional=self.optional,
3531 default=self == self.default,
3532 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3533 expl=None if self._expl is None else tag_decode(self._expl),
3538 expl_offset=self.expl_offset if self.expled else None,
3539 expl_tlen=self.expl_tlen if self.expled else None,
3540 expl_llen=self.expl_llen if self.expled else None,
3541 expl_vlen=self.expl_vlen if self.expled else None,
3542 expl_lenindef=self.expl_lenindef,
3543 lenindef=self.lenindef,
3544 ber_encoded=self.ber_encoded,
3547 defined_by, defined = self.defined or (None, None)
3548 if defined_by is not None:
3550 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3552 for pp in self.pps_lenindef(decode_path):
3556 def agg_octet_string(evgens, decode_path, raw, writer):
3557 """Aggregate constructed string (OctetString and its derivatives)
3559 :param evgens: iterator of generated events
3560 :param decode_path: points to the string we want to decode
3561 :param raw: slicebable (memoryview, bytearray, etc) with
3562 the data evgens are generated one
3563 :param writer: buffer.write where string is going to be saved
3565 decode_path_len = len(decode_path)
3566 for dp, obj, _ in evgens:
3567 if dp[:decode_path_len] != decode_path:
3569 if not obj.ber_encoded:
3570 write_full(writer, raw[
3571 obj.offset + obj.tlen + obj.llen:
3572 obj.offset + obj.tlen + obj.llen + obj.vlen -
3573 (EOC_LEN if obj.expl_lenindef else 0)
3575 if len(dp) == decode_path_len:
3579 NullState = namedtuple("NullState", BasicState._fields, **NAMEDTUPLE_KWARGS)
3583 """``NULL`` null object
3591 tag_default = tag_encode(5)
3592 asn1_type_name = "NULL"
3596 value=None, # unused, but Sequence passes it
3603 :param bytes impl: override default tag with ``IMPLICIT`` one
3604 :param bytes expl: override default tag with ``EXPLICIT`` one
3605 :param bool optional: is object ``OPTIONAL`` in sequence
3607 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3614 def __getstate__(self):
3630 def __eq__(self, their):
3631 if not issubclass(their.__class__, Null):
3634 self.tag == their.tag and
3635 self._expl == their._expl
3645 return self.__class__(
3646 impl=self.tag if impl is None else impl,
3647 expl=self._expl if expl is None else expl,
3648 optional=self.optional if optional is None else optional,
3652 return self.tag + len_encode(0)
3654 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3656 t, _, lv = tag_strip(tlv)
3657 except DecodeError as err:
3658 raise err.__class__(
3660 klass=self.__class__,
3661 decode_path=decode_path,
3666 klass=self.__class__,
3667 decode_path=decode_path,
3670 if tag_only: # pragma: no cover
3674 l, _, v = len_decode(lv)
3675 except DecodeError as err:
3676 raise err.__class__(
3678 klass=self.__class__,
3679 decode_path=decode_path,
3683 raise InvalidLength(
3684 "Null must have zero length",
3685 klass=self.__class__,
3686 decode_path=decode_path,
3689 obj = self.__class__(
3692 optional=self.optional,
3693 _decoded=(offset, 1, 0),
3695 yield decode_path, obj, v
3698 return pp_console_row(next(self.pps()))
3700 def pps(self, decode_path=()):
3703 asn1_type_name=self.asn1_type_name,
3704 obj_name=self.__class__.__name__,
3705 decode_path=decode_path,
3706 optional=self.optional,
3707 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3708 expl=None if self._expl is None else tag_decode(self._expl),
3713 expl_offset=self.expl_offset if self.expled else None,
3714 expl_tlen=self.expl_tlen if self.expled else None,
3715 expl_llen=self.expl_llen if self.expled else None,
3716 expl_vlen=self.expl_vlen if self.expled else None,
3717 expl_lenindef=self.expl_lenindef,
3720 for pp in self.pps_lenindef(decode_path):
3724 ObjectIdentifierState = namedtuple(
3725 "ObjectIdentifierState",
3726 BasicState._fields + ("value", "defines"),
3731 class ObjectIdentifier(Obj):
3732 """``OBJECT IDENTIFIER`` OID type
3734 >>> oid = ObjectIdentifier((1, 2, 3))
3735 OBJECT IDENTIFIER 1.2.3
3736 >>> oid == ObjectIdentifier("1.2.3")
3742 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3743 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3745 >>> str(ObjectIdentifier((3, 1)))
3746 Traceback (most recent call last):
3747 pyderasn.InvalidOID: unacceptable first arc value
3749 __slots__ = ("defines",)
3750 tag_default = tag_encode(6)
3751 asn1_type_name = "OBJECT IDENTIFIER"
3764 :param value: set the value. Either tuples of integers,
3765 string of "."-concatenated integers, or
3766 :py:class:`pyderasn.ObjectIdentifier` object
3767 :param defines: sequence of tuples. Each tuple has two elements.
3768 First one is relative to current one decode
3769 path, aiming to the field defined by that OID.
3770 Read about relative path in
3771 :py:func:`pyderasn.abs_decode_path`. Second
3772 tuple element is ``{OID: pyderasn.Obj()}``
3773 dictionary, mapping between current OID value
3774 and structure applied to defined field.
3775 :ref:`Read about DEFINED BY <definedby>`
3776 :param bytes impl: override default tag with ``IMPLICIT`` one
3777 :param bytes expl: override default tag with ``EXPLICIT`` one
3778 :param default: set default value. Type same as in ``value``
3779 :param bool optional: is object ``OPTIONAL`` in sequence
3781 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3783 if value is not None:
3784 self._value = self._value_sanitize(value)
3785 if default is not None:
3786 default = self._value_sanitize(default)
3787 self.default = self.__class__(
3792 if self._value is None:
3793 self._value = default
3794 self.defines = defines
3796 def __add__(self, their):
3797 if their.__class__ == tuple:
3798 return self.__class__(self._value + their)
3799 if isinstance(their, self.__class__):
3800 return self.__class__(self._value + their._value)
3801 raise InvalidValueType((self.__class__, tuple))
3803 def _value_sanitize(self, value):
3804 if issubclass(value.__class__, ObjectIdentifier):
3806 if isinstance(value, string_types):
3808 value = tuple(pureint(arc) for arc in value.split("."))
3810 raise InvalidOID("unacceptable arcs values")
3811 if value.__class__ == tuple:
3813 raise InvalidOID("less than 2 arcs")
3814 first_arc = value[0]
3815 if first_arc in (0, 1):
3816 if not (0 <= value[1] <= 39):
3817 raise InvalidOID("second arc is too wide")
3818 elif first_arc == 2:
3821 raise InvalidOID("unacceptable first arc value")
3822 if not all(arc >= 0 for arc in value):
3823 raise InvalidOID("negative arc value")
3825 raise InvalidValueType((self.__class__, str, tuple))
3829 return self._value is not None
3831 def __getstate__(self):
3832 return ObjectIdentifierState(
3849 def __setstate__(self, state):
3850 super(ObjectIdentifier, self).__setstate__(state)
3851 self._value = state.value
3852 self.defines = state.defines
3855 self._assert_ready()
3856 return iter(self._value)
3859 return ".".join(str(arc) for arc in self._value or ())
3862 self._assert_ready()
3865 bytes(self._expl or b"") +
3866 str(self._value).encode("ascii"),
3869 def __eq__(self, their):
3870 if their.__class__ == tuple:
3871 return self._value == their
3872 if not issubclass(their.__class__, ObjectIdentifier):
3875 self.tag == their.tag and
3876 self._expl == their._expl and
3877 self._value == their._value
3880 def __lt__(self, their):
3881 return self._value < their._value
3892 return self.__class__(
3894 defines=self.defines if defines is None else defines,
3895 impl=self.tag if impl is None else impl,
3896 expl=self._expl if expl is None else expl,
3897 default=self.default if default is None else default,
3898 optional=self.optional if optional is None else optional,
3902 self._assert_ready()
3904 first_value = value[1]
3905 first_arc = value[0]
3908 elif first_arc == 1:
3910 elif first_arc == 2:
3912 else: # pragma: no cover
3913 raise RuntimeError("invalid arc is stored")
3914 octets = [zero_ended_encode(first_value)]
3915 for arc in value[2:]:
3916 octets.append(zero_ended_encode(arc))
3917 v = b"".join(octets)
3918 return b"".join((self.tag, len_encode(len(v)), v))
3920 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3922 t, _, lv = tag_strip(tlv)
3923 except DecodeError as err:
3924 raise err.__class__(
3926 klass=self.__class__,
3927 decode_path=decode_path,
3932 klass=self.__class__,
3933 decode_path=decode_path,
3936 if tag_only: # pragma: no cover
3940 l, llen, v = len_decode(lv)
3941 except DecodeError as err:
3942 raise err.__class__(
3944 klass=self.__class__,
3945 decode_path=decode_path,
3949 raise NotEnoughData(
3950 "encoded length is longer than data",
3951 klass=self.__class__,
3952 decode_path=decode_path,
3956 raise NotEnoughData(
3958 klass=self.__class__,
3959 decode_path=decode_path,
3962 v, tail = v[:l], v[l:]
3969 octet = indexbytes(v, i)
3970 if i == 0 and octet == 0x80:
3971 if ctx.get("bered", False):
3974 raise DecodeError("non normalized arc encoding")
3975 arc = (arc << 7) | (octet & 0x7F)
3976 if octet & 0x80 == 0:
3984 klass=self.__class__,
3985 decode_path=decode_path,
3989 second_arc = arcs[0]
3990 if 0 <= second_arc <= 39:
3992 elif 40 <= second_arc <= 79:
3998 obj = self.__class__(
3999 value=tuple([first_arc, second_arc] + arcs[1:]),
4002 default=self.default,
4003 optional=self.optional,
4004 _decoded=(offset, llen, l),
4007 obj.ber_encoded = True
4008 yield decode_path, obj, tail
4011 return pp_console_row(next(self.pps()))
4013 def pps(self, decode_path=()):
4016 asn1_type_name=self.asn1_type_name,
4017 obj_name=self.__class__.__name__,
4018 decode_path=decode_path,
4019 value=str(self) if self.ready else None,
4020 optional=self.optional,
4021 default=self == self.default,
4022 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4023 expl=None if self._expl is None else tag_decode(self._expl),
4028 expl_offset=self.expl_offset if self.expled else None,
4029 expl_tlen=self.expl_tlen if self.expled else None,
4030 expl_llen=self.expl_llen if self.expled else None,
4031 expl_vlen=self.expl_vlen if self.expled else None,
4032 expl_lenindef=self.expl_lenindef,
4033 ber_encoded=self.ber_encoded,
4036 for pp in self.pps_lenindef(decode_path):
4040 class Enumerated(Integer):
4041 """``ENUMERATED`` integer type
4043 This type is identical to :py:class:`pyderasn.Integer`, but requires
4044 schema to be specified and does not accept values missing from it.
4047 tag_default = tag_encode(10)
4048 asn1_type_name = "ENUMERATED"
4059 bounds=None, # dummy argument, workability for Integer.decode
4061 super(Enumerated, self).__init__(
4062 value, bounds, impl, expl, default, optional, _specs, _decoded,
4064 if len(self.specs) == 0:
4065 raise ValueError("schema must be specified")
4067 def _value_sanitize(self, value):
4068 if isinstance(value, self.__class__):
4069 value = value._value
4070 elif isinstance(value, integer_types):
4071 for _value in itervalues(self.specs):
4076 "unknown integer value: %s" % value,
4077 klass=self.__class__,
4079 elif isinstance(value, string_types):
4080 value = self.specs.get(value)
4082 raise ObjUnknown("integer value: %s" % value)
4084 raise InvalidValueType((self.__class__, int, str))
4096 return self.__class__(
4098 impl=self.tag if impl is None else impl,
4099 expl=self._expl if expl is None else expl,
4100 default=self.default if default is None else default,
4101 optional=self.optional if optional is None else optional,
4106 def escape_control_unicode(c):
4107 if unicat(c)[0] == "C":
4108 c = repr(c).lstrip("u").strip("'")
4112 class CommonString(OctetString):
4113 """Common class for all strings
4115 Everything resembles :py:class:`pyderasn.OctetString`, except
4116 ability to deal with unicode text strings.
4118 >>> hexenc("привет мир".encode("utf-8"))
4119 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
4120 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
4122 >>> s = UTF8String("привет мир")
4123 UTF8String UTF8String привет мир
4125 'привет мир'
4126 >>> hexenc(bytes(s))
4127 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
4129 >>> PrintableString("привет мир")
4130 Traceback (most recent call last):
4131 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
4133 >>> BMPString("ада", bounds=(2, 2))
4134 Traceback (most recent call last):
4135 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
4136 >>> s = BMPString("ад", bounds=(2, 2))
4139 >>> hexenc(bytes(s))
4147 * - :py:class:`pyderasn.UTF8String`
4149 * - :py:class:`pyderasn.NumericString`
4151 * - :py:class:`pyderasn.PrintableString`
4153 * - :py:class:`pyderasn.TeletexString`
4155 * - :py:class:`pyderasn.T61String`
4157 * - :py:class:`pyderasn.VideotexString`
4159 * - :py:class:`pyderasn.IA5String`
4161 * - :py:class:`pyderasn.GraphicString`
4163 * - :py:class:`pyderasn.VisibleString`
4165 * - :py:class:`pyderasn.ISO646String`
4167 * - :py:class:`pyderasn.GeneralString`
4169 * - :py:class:`pyderasn.UniversalString`
4171 * - :py:class:`pyderasn.BMPString`
4176 def _value_sanitize(self, value):
4178 value_decoded = None
4179 if isinstance(value, self.__class__):
4180 value_raw = value._value
4181 elif value.__class__ == text_type:
4182 value_decoded = value
4183 elif value.__class__ == binary_type:
4186 raise InvalidValueType((self.__class__, text_type, binary_type))
4189 value_decoded.encode(self.encoding)
4190 if value_raw is None else value_raw
4193 value_raw.decode(self.encoding)
4194 if value_decoded is None else value_decoded
4196 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4197 raise DecodeError(str(err))
4198 if not self._bound_min <= len(value_decoded) <= self._bound_max:
4206 def __eq__(self, their):
4207 if their.__class__ == binary_type:
4208 return self._value == their
4209 if their.__class__ == text_type:
4210 return self._value == their.encode(self.encoding)
4211 if not isinstance(their, self.__class__):
4214 self._value == their._value and
4215 self.tag == their.tag and
4216 self._expl == their._expl
4219 def __unicode__(self):
4221 return self._value.decode(self.encoding)
4222 return text_type(self._value)
4225 return pp_console_row(next(self.pps(no_unicode=PY2)))
4227 def pps(self, decode_path=(), no_unicode=False):
4231 hexenc(bytes(self)) if no_unicode else
4232 "".join(escape_control_unicode(c) for c in self.__unicode__())
4236 asn1_type_name=self.asn1_type_name,
4237 obj_name=self.__class__.__name__,
4238 decode_path=decode_path,
4240 optional=self.optional,
4241 default=self == self.default,
4242 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4243 expl=None if self._expl is None else tag_decode(self._expl),
4248 expl_offset=self.expl_offset if self.expled else None,
4249 expl_tlen=self.expl_tlen if self.expled else None,
4250 expl_llen=self.expl_llen if self.expled else None,
4251 expl_vlen=self.expl_vlen if self.expled else None,
4252 expl_lenindef=self.expl_lenindef,
4253 ber_encoded=self.ber_encoded,
4256 for pp in self.pps_lenindef(decode_path):
4260 class UTF8String(CommonString):
4262 tag_default = tag_encode(12)
4264 asn1_type_name = "UTF8String"
4267 class AllowableCharsMixin(object):
4269 def allowable_chars(self):
4271 return self._allowable_chars
4272 return frozenset(six_unichr(c) for c in self._allowable_chars)
4275 class NumericString(AllowableCharsMixin, CommonString):
4278 Its value is properly sanitized: only ASCII digits with spaces can
4281 >>> NumericString().allowable_chars
4282 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
4285 tag_default = tag_encode(18)
4287 asn1_type_name = "NumericString"
4288 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
4290 def _value_sanitize(self, value):
4291 value = super(NumericString, self)._value_sanitize(value)
4292 if not frozenset(value) <= self._allowable_chars:
4293 raise DecodeError("non-numeric value")
4297 PrintableStringState = namedtuple(
4298 "PrintableStringState",
4299 OctetStringState._fields + ("allowable_chars",),
4304 class PrintableString(AllowableCharsMixin, CommonString):
4307 Its value is properly sanitized: see X.680 41.4 table 10.
4309 >>> PrintableString().allowable_chars
4310 frozenset([' ', "'", ..., 'z'])
4311 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4312 PrintableString PrintableString foo*bar
4313 >>> obj.allow_asterisk, obj.allow_ampersand
4317 tag_default = tag_encode(19)
4319 asn1_type_name = "PrintableString"
4320 _allowable_chars = frozenset(
4321 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4323 _asterisk = frozenset("*".encode("ascii"))
4324 _ampersand = frozenset("&".encode("ascii"))
4336 allow_asterisk=False,
4337 allow_ampersand=False,
4340 :param allow_asterisk: allow asterisk character
4341 :param allow_ampersand: allow ampersand character
4344 self._allowable_chars |= self._asterisk
4346 self._allowable_chars |= self._ampersand
4347 super(PrintableString, self).__init__(
4348 value, bounds, impl, expl, default, optional, _decoded, ctx,
4352 def allow_asterisk(self):
4353 """Is asterisk character allowed?
4355 return self._asterisk <= self._allowable_chars
4358 def allow_ampersand(self):
4359 """Is ampersand character allowed?
4361 return self._ampersand <= self._allowable_chars
4363 def _value_sanitize(self, value):
4364 value = super(PrintableString, self)._value_sanitize(value)
4365 if not frozenset(value) <= self._allowable_chars:
4366 raise DecodeError("non-printable value")
4369 def __getstate__(self):
4370 return PrintableStringState(
4371 *super(PrintableString, self).__getstate__(),
4372 **{"allowable_chars": self._allowable_chars}
4375 def __setstate__(self, state):
4376 super(PrintableString, self).__setstate__(state)
4377 self._allowable_chars = state.allowable_chars
4388 return self.__class__(
4391 (self._bound_min, self._bound_max)
4392 if bounds is None else bounds
4394 impl=self.tag if impl is None else impl,
4395 expl=self._expl if expl is None else expl,
4396 default=self.default if default is None else default,
4397 optional=self.optional if optional is None else optional,
4398 allow_asterisk=self.allow_asterisk,
4399 allow_ampersand=self.allow_ampersand,
4403 class TeletexString(CommonString):
4405 tag_default = tag_encode(20)
4407 asn1_type_name = "TeletexString"
4410 class T61String(TeletexString):
4412 asn1_type_name = "T61String"
4415 class VideotexString(CommonString):
4417 tag_default = tag_encode(21)
4418 encoding = "iso-8859-1"
4419 asn1_type_name = "VideotexString"
4422 class IA5String(CommonString):
4424 tag_default = tag_encode(22)
4426 asn1_type_name = "IA5"
4429 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4430 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4431 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4434 class VisibleString(CommonString):
4436 tag_default = tag_encode(26)
4438 asn1_type_name = "VisibleString"
4441 UTCTimeState = namedtuple(
4443 OctetStringState._fields + ("ber_raw",),
4448 def str_to_time_fractions(value):
4450 year, v = (v // 10**10), (v % 10**10)
4451 month, v = (v // 10**8), (v % 10**8)
4452 day, v = (v // 10**6), (v % 10**6)
4453 hour, v = (v // 10**4), (v % 10**4)
4454 minute, second = (v // 100), (v % 100)
4455 return year, month, day, hour, minute, second
4458 class UTCTime(VisibleString):
4459 """``UTCTime`` datetime type
4461 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4462 UTCTime UTCTime 2017-09-30T22:07:50
4468 datetime.datetime(2017, 9, 30, 22, 7, 50)
4469 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4470 datetime.datetime(1957, 9, 30, 22, 7, 50)
4472 If BER encoded value was met, then ``ber_raw`` attribute will hold
4473 its raw representation.
4477 Pay attention that UTCTime can not hold full year, so all years
4478 having < 50 years are treated as 20xx, 19xx otherwise, according
4479 to X.509 recommendation.
4483 No strict validation of UTC offsets are made, but very crude:
4485 * minutes are not exceeding 60
4486 * offset value is not exceeding 14 hours
4488 __slots__ = ("ber_raw",)
4489 tag_default = tag_encode(23)
4491 asn1_type_name = "UTCTime"
4492 evgen_mode_skip_value = False
4502 bounds=None, # dummy argument, workability for OctetString.decode
4506 :param value: set the value. Either datetime type, or
4507 :py:class:`pyderasn.UTCTime` object
4508 :param bytes impl: override default tag with ``IMPLICIT`` one
4509 :param bytes expl: override default tag with ``EXPLICIT`` one
4510 :param default: set default value. Type same as in ``value``
4511 :param bool optional: is object ``OPTIONAL`` in sequence
4513 super(UTCTime, self).__init__(
4514 None, None, impl, expl, None, optional, _decoded, ctx,
4518 if value is not None:
4519 self._value, self.ber_raw = self._value_sanitize(value, ctx)
4520 self.ber_encoded = self.ber_raw is not None
4521 if default is not None:
4522 default, _ = self._value_sanitize(default)
4523 self.default = self.__class__(
4528 if self._value is None:
4529 self._value = default
4531 self.optional = optional
4533 def _strptime_bered(self, value):
4534 year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
4537 raise ValueError("no timezone")
4538 year += 2000 if year < 50 else 1900
4539 decoded = datetime(year, month, day, hour, minute)
4541 if value[-1] == "Z":
4545 raise ValueError("invalid UTC offset")
4546 if value[-5] == "-":
4548 elif value[-5] == "+":
4551 raise ValueError("invalid UTC offset")
4552 v = pureint(value[-4:])
4553 offset, v = (60 * (v % 100)), v // 100
4555 raise ValueError("invalid UTC offset minutes")
4557 if offset > 14 * 3600:
4558 raise ValueError("too big UTC offset")
4562 return offset, decoded
4564 raise ValueError("invalid UTC offset seconds")
4565 seconds = pureint(value)
4567 raise ValueError("invalid seconds value")
4568 return offset, decoded + timedelta(seconds=seconds)
4570 def _strptime(self, value):
4571 # datetime.strptime's format: %y%m%d%H%M%SZ
4572 if len(value) != LEN_YYMMDDHHMMSSZ:
4573 raise ValueError("invalid UTCTime length")
4574 if value[-1] != "Z":
4575 raise ValueError("non UTC timezone")
4576 year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
4577 year += 2000 if year < 50 else 1900
4578 return datetime(year, month, day, hour, minute, second)
4580 def _dt_sanitize(self, value):
4581 if value.year < 1950 or value.year > 2049:
4582 raise ValueError("UTCTime can hold only 1950-2049 years")
4583 return value.replace(microsecond=0)
4585 def _value_sanitize(self, value, ctx=None):
4586 if value.__class__ == binary_type:
4588 value_decoded = value.decode("ascii")
4589 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4590 raise DecodeError("invalid UTCTime encoding: %r" % err)
4593 return self._strptime(value_decoded), None
4594 except (TypeError, ValueError) as _err:
4596 if (ctx is not None) and ctx.get("bered", False):
4598 offset, _value = self._strptime_bered(value_decoded)
4599 _value = _value - timedelta(seconds=offset)
4600 return self._dt_sanitize(_value), value
4601 except (TypeError, ValueError, OverflowError) as _err:
4604 "invalid %s format: %r" % (self.asn1_type_name, err),
4605 klass=self.__class__,
4607 if isinstance(value, self.__class__):
4608 return value._value, None
4609 if value.__class__ == datetime:
4610 return self._dt_sanitize(value), None
4611 raise InvalidValueType((self.__class__, datetime))
4613 def _pp_value(self):
4615 value = self._value.isoformat()
4616 if self.ber_encoded:
4617 value += " (%s)" % self.ber_raw
4620 def __unicode__(self):
4622 value = self._value.isoformat()
4623 if self.ber_encoded:
4624 value += " (%s)" % self.ber_raw
4626 return text_type(self._pp_value())
4628 def __getstate__(self):
4629 return UTCTimeState(
4630 *super(UTCTime, self).__getstate__(),
4631 **{"ber_raw": self.ber_raw}
4634 def __setstate__(self, state):
4635 super(UTCTime, self).__setstate__(state)
4636 self.ber_raw = state.ber_raw
4638 def __bytes__(self):
4639 self._assert_ready()
4640 return self._encode_time()
4642 def __eq__(self, their):
4643 if their.__class__ == binary_type:
4644 return self._encode_time() == their
4645 if their.__class__ == datetime:
4646 return self.todatetime() == their
4647 if not isinstance(their, self.__class__):
4650 self._value == their._value and
4651 self.tag == their.tag and
4652 self._expl == their._expl
4655 def _encode_time(self):
4656 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4659 self._assert_ready()
4660 value = self._encode_time()
4661 return b"".join((self.tag, len_encode(len(value)), value))
4663 def _encode_cer(self, writer):
4664 write_full(writer, self._encode())
4666 def todatetime(self):
4670 return pp_console_row(next(self.pps()))
4672 def pps(self, decode_path=()):
4675 asn1_type_name=self.asn1_type_name,
4676 obj_name=self.__class__.__name__,
4677 decode_path=decode_path,
4678 value=self._pp_value(),
4679 optional=self.optional,
4680 default=self == self.default,
4681 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4682 expl=None if self._expl is None else tag_decode(self._expl),
4687 expl_offset=self.expl_offset if self.expled else None,
4688 expl_tlen=self.expl_tlen if self.expled else None,
4689 expl_llen=self.expl_llen if self.expled else None,
4690 expl_vlen=self.expl_vlen if self.expled else None,
4691 expl_lenindef=self.expl_lenindef,
4692 ber_encoded=self.ber_encoded,
4695 for pp in self.pps_lenindef(decode_path):
4699 class GeneralizedTime(UTCTime):
4700 """``GeneralizedTime`` datetime type
4702 This type is similar to :py:class:`pyderasn.UTCTime`.
4704 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4705 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4707 '20170930220750.000123Z'
4708 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4709 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4713 Only microsecond fractions are supported in DER encoding.
4714 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4715 higher precision values.
4719 BER encoded data can loss information (accuracy) during decoding
4720 because of float transformations.
4724 Local times (without explicit timezone specification) are treated
4725 as UTC one, no transformations are made.
4729 Zero year is unsupported.
4732 tag_default = tag_encode(24)
4733 asn1_type_name = "GeneralizedTime"
4735 def _dt_sanitize(self, value):
4738 def _strptime_bered(self, value):
4739 if len(value) < 4 + 3 * 2:
4740 raise ValueError("invalid GeneralizedTime")
4741 year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
4742 decoded = datetime(year, month, day, hour)
4743 offset, value = 0, value[10:]
4745 return offset, decoded
4746 if value[-1] == "Z":
4749 for char, sign in (("-", -1), ("+", 1)):
4750 idx = value.rfind(char)
4753 offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
4754 v = pureint(offset_raw)
4755 if len(offset_raw) == 4:
4756 offset, v = (60 * (v % 100)), v // 100
4758 raise ValueError("invalid UTC offset minutes")
4759 elif len(offset_raw) == 2:
4762 raise ValueError("invalid UTC offset")
4764 if offset > 14 * 3600:
4765 raise ValueError("too big UTC offset")
4769 return offset, decoded
4770 if value[0] in DECIMAL_SIGNS:
4772 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4775 raise ValueError("stripped minutes")
4776 decoded += timedelta(seconds=60 * pureint(value[:2]))
4779 return offset, decoded
4780 if value[0] in DECIMAL_SIGNS:
4782 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4785 raise ValueError("stripped seconds")
4786 decoded += timedelta(seconds=pureint(value[:2]))
4789 return offset, decoded
4790 if value[0] not in DECIMAL_SIGNS:
4791 raise ValueError("invalid format after seconds")
4793 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4796 def _strptime(self, value):
4798 if l == LEN_YYYYMMDDHHMMSSZ:
4799 # datetime.strptime's format: %Y%m%d%H%M%SZ
4800 if value[-1] != "Z":
4801 raise ValueError("non UTC timezone")
4802 return datetime(*str_to_time_fractions(value[:-1]))
4803 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4804 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4805 if value[-1] != "Z":
4806 raise ValueError("non UTC timezone")
4807 if value[14] != ".":
4808 raise ValueError("no fractions separator")
4811 raise ValueError("trailing zero")
4814 raise ValueError("only microsecond fractions are supported")
4815 us = pureint(us + ("0" * (6 - us_len)))
4816 year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
4817 return datetime(year, month, day, hour, minute, second, us)
4818 raise ValueError("invalid GeneralizedTime length")
4820 def _encode_time(self):
4822 encoded = value.strftime("%Y%m%d%H%M%S")
4823 if value.microsecond > 0:
4824 encoded += (".%06d" % value.microsecond).rstrip("0")
4825 return (encoded + "Z").encode("ascii")
4828 class GraphicString(CommonString):
4830 tag_default = tag_encode(25)
4831 encoding = "iso-8859-1"
4832 asn1_type_name = "GraphicString"
4835 class ISO646String(VisibleString):
4837 asn1_type_name = "ISO646String"
4840 class GeneralString(CommonString):
4842 tag_default = tag_encode(27)
4843 encoding = "iso-8859-1"
4844 asn1_type_name = "GeneralString"
4847 class UniversalString(CommonString):
4849 tag_default = tag_encode(28)
4850 encoding = "utf-32-be"
4851 asn1_type_name = "UniversalString"
4854 class BMPString(CommonString):
4856 tag_default = tag_encode(30)
4857 encoding = "utf-16-be"
4858 asn1_type_name = "BMPString"
4861 ChoiceState = namedtuple(
4863 BasicState._fields + ("specs", "value",),
4869 """``CHOICE`` special type
4873 class GeneralName(Choice):
4875 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4876 ("dNSName", IA5String(impl=tag_ctxp(2))),
4879 >>> gn = GeneralName()
4881 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4882 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4883 >>> gn["dNSName"] = IA5String("bar.baz")
4884 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4885 >>> gn["rfc822Name"]
4888 [2] IA5String IA5 bar.baz
4891 >>> gn.value == gn["dNSName"]
4894 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4896 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4897 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4899 __slots__ = ("specs",)
4901 asn1_type_name = "CHOICE"
4914 :param value: set the value. Either ``(choice, value)`` tuple, or
4915 :py:class:`pyderasn.Choice` object
4916 :param bytes impl: can not be set, do **not** use it
4917 :param bytes expl: override default tag with ``EXPLICIT`` one
4918 :param default: set default value. Type same as in ``value``
4919 :param bool optional: is object ``OPTIONAL`` in sequence
4921 if impl is not None:
4922 raise ValueError("no implicit tag allowed for CHOICE")
4923 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4925 schema = getattr(self, "schema", ())
4926 if len(schema) == 0:
4927 raise ValueError("schema must be specified")
4929 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
4932 if value is not None:
4933 self._value = self._value_sanitize(value)
4934 if default is not None:
4935 default_value = self._value_sanitize(default)
4936 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4937 default_obj.specs = self.specs
4938 default_obj._value = default_value
4939 self.default = default_obj
4941 self._value = copy(default_obj._value)
4942 if self._expl is not None:
4943 tag_class, _, tag_num = tag_decode(self._expl)
4944 self._tag_order = (tag_class, tag_num)
4946 def _value_sanitize(self, value):
4947 if (value.__class__ == tuple) and len(value) == 2:
4949 spec = self.specs.get(choice)
4951 raise ObjUnknown(choice)
4952 if not isinstance(obj, spec.__class__):
4953 raise InvalidValueType((spec,))
4954 return (choice, spec(obj))
4955 if isinstance(value, self.__class__):
4957 raise InvalidValueType((self.__class__, tuple))
4961 return self._value is not None and self._value[1].ready
4965 return self.expl_lenindef or (
4966 (self._value is not None) and
4967 self._value[1].bered
4970 def __getstate__(self):
4988 def __setstate__(self, state):
4989 super(Choice, self).__setstate__(state)
4990 self.specs = state.specs
4991 self._value = state.value
4993 def __eq__(self, their):
4994 if (their.__class__ == tuple) and len(their) == 2:
4995 return self._value == their
4996 if not isinstance(their, self.__class__):
4999 self.specs == their.specs and
5000 self._value == their._value
5010 return self.__class__(
5013 expl=self._expl if expl is None else expl,
5014 default=self.default if default is None else default,
5015 optional=self.optional if optional is None else optional,
5020 """Name of the choice
5022 self._assert_ready()
5023 return self._value[0]
5027 """Value of underlying choice
5029 self._assert_ready()
5030 return self._value[1]
5033 def tag_order(self):
5034 self._assert_ready()
5035 return self._value[1].tag_order if self._tag_order is None else self._tag_order
5038 def tag_order_cer(self):
5039 return min(v.tag_order_cer for v in itervalues(self.specs))
5041 def __getitem__(self, key):
5042 if key not in self.specs:
5043 raise ObjUnknown(key)
5044 if self._value is None:
5046 choice, value = self._value
5051 def __setitem__(self, key, value):
5052 spec = self.specs.get(key)
5054 raise ObjUnknown(key)
5055 if not isinstance(value, spec.__class__):
5056 raise InvalidValueType((spec.__class__,))
5057 self._value = (key, spec(value))
5065 return self._value[1].decoded if self.ready else False
5068 self._assert_ready()
5069 return self._value[1].encode()
5071 def _encode_cer(self, writer):
5072 self._assert_ready()
5073 self._value[1].encode_cer(writer)
5075 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5076 for choice, spec in iteritems(self.specs):
5077 sub_decode_path = decode_path + (choice,)
5083 decode_path=sub_decode_path,
5086 _ctx_immutable=False,
5093 klass=self.__class__,
5094 decode_path=decode_path,
5097 if tag_only: # pragma: no cover
5101 for _decode_path, value, tail in spec.decode_evgen(
5105 decode_path=sub_decode_path,
5107 _ctx_immutable=False,
5109 yield _decode_path, value, tail
5111 _, value, tail = next(spec.decode_evgen(
5115 decode_path=sub_decode_path,
5117 _ctx_immutable=False,
5120 obj = self.__class__(
5123 default=self.default,
5124 optional=self.optional,
5125 _decoded=(offset, 0, value.fulllen),
5127 obj._value = (choice, value)
5128 yield decode_path, obj, tail
5131 value = pp_console_row(next(self.pps()))
5133 value = "%s[%r]" % (value, self.value)
5136 def pps(self, decode_path=()):
5139 asn1_type_name=self.asn1_type_name,
5140 obj_name=self.__class__.__name__,
5141 decode_path=decode_path,
5142 value=self.choice if self.ready else None,
5143 optional=self.optional,
5144 default=self == self.default,
5145 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5146 expl=None if self._expl is None else tag_decode(self._expl),
5151 expl_lenindef=self.expl_lenindef,
5155 yield self.value.pps(decode_path=decode_path + (self.choice,))
5156 for pp in self.pps_lenindef(decode_path):
5160 class PrimitiveTypes(Choice):
5161 """Predefined ``CHOICE`` for all generic primitive types
5163 It could be useful for general decoding of some unspecified values:
5165 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
5166 OCTET STRING 3 bytes 666f6f
5167 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
5171 schema = tuple((klass.__name__, klass()) for klass in (
5195 AnyState = namedtuple(
5197 BasicState._fields + ("value", "defined"),
5203 """``ANY`` special type
5205 >>> Any(Integer(-123))
5206 ANY INTEGER -123 (0X:7B)
5207 >>> a = Any(OctetString(b"hello world").encode())
5208 ANY 040b68656c6c6f20776f726c64
5209 >>> hexenc(bytes(a))
5210 b'0x040x0bhello world'
5212 __slots__ = ("defined",)
5213 tag_default = tag_encode(0)
5214 asn1_type_name = "ANY"
5224 :param value: set the value. Either any kind of pyderasn's
5225 **ready** object, or bytes. Pay attention that
5226 **no** validation is performed if raw binary value
5227 is valid TLV, except just tag decoding
5228 :param bytes expl: override default tag with ``EXPLICIT`` one
5229 :param bool optional: is object ``OPTIONAL`` in sequence
5231 super(Any, self).__init__(None, expl, None, optional, _decoded)
5235 value = self._value_sanitize(value)
5237 if self._expl is None:
5238 if value.__class__ == binary_type:
5239 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5241 tag_class, tag_num = value.tag_order
5243 tag_class, _, tag_num = tag_decode(self._expl)
5244 self._tag_order = (tag_class, tag_num)
5247 def _value_sanitize(self, value):
5248 if value.__class__ == binary_type:
5250 raise ValueError("Any value can not be empty")
5252 if isinstance(value, self.__class__):
5254 if not isinstance(value, Obj):
5255 raise InvalidValueType((self.__class__, Obj, binary_type))
5260 return self._value is not None
5263 def tag_order(self):
5264 self._assert_ready()
5265 return self._tag_order
5269 if self.expl_lenindef or self.lenindef:
5271 if self.defined is None:
5273 return self.defined[1].bered
5275 def __getstate__(self):
5293 def __setstate__(self, state):
5294 super(Any, self).__setstate__(state)
5295 self._value = state.value
5296 self.defined = state.defined
5298 def __eq__(self, their):
5299 if their.__class__ == binary_type:
5300 if self._value.__class__ == binary_type:
5301 return self._value == their
5302 return self._value.encode() == their
5303 if issubclass(their.__class__, Any):
5304 if self.ready and their.ready:
5305 return bytes(self) == bytes(their)
5306 return self.ready == their.ready
5315 return self.__class__(
5317 expl=self._expl if expl is None else expl,
5318 optional=self.optional if optional is None else optional,
5321 def __bytes__(self):
5322 self._assert_ready()
5324 if value.__class__ == binary_type:
5326 return self._value.encode()
5333 self._assert_ready()
5335 if value.__class__ == binary_type:
5337 return value.encode()
5339 def _encode_cer(self, writer):
5340 self._assert_ready()
5342 if value.__class__ == binary_type:
5343 write_full(writer, value)
5345 value.encode_cer(writer)
5347 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5349 t, tlen, lv = tag_strip(tlv)
5350 except DecodeError as err:
5351 raise err.__class__(
5353 klass=self.__class__,
5354 decode_path=decode_path,
5358 l, llen, v = len_decode(lv)
5359 except LenIndefForm as err:
5360 if not ctx.get("bered", False):
5361 raise err.__class__(
5363 klass=self.__class__,
5364 decode_path=decode_path,
5367 llen, vlen, v = 1, 0, lv[1:]
5368 sub_offset = offset + tlen + llen
5370 while v[:EOC_LEN].tobytes() != EOC:
5371 chunk, v = Any().decode(
5374 decode_path=decode_path + (str(chunk_i),),
5377 _ctx_immutable=False,
5379 vlen += chunk.tlvlen
5380 sub_offset += chunk.tlvlen
5382 tlvlen = tlen + llen + vlen + EOC_LEN
5383 obj = self.__class__(
5384 value=None if evgen_mode else tlv[:tlvlen].tobytes(),
5386 optional=self.optional,
5387 _decoded=(offset, 0, tlvlen),
5390 obj.tag = t.tobytes()
5391 yield decode_path, obj, v[EOC_LEN:]
5393 except DecodeError as err:
5394 raise err.__class__(
5396 klass=self.__class__,
5397 decode_path=decode_path,
5401 raise NotEnoughData(
5402 "encoded length is longer than data",
5403 klass=self.__class__,
5404 decode_path=decode_path,
5407 tlvlen = tlen + llen + l
5408 v, tail = tlv[:tlvlen], v[l:]
5409 obj = self.__class__(
5410 value=None if evgen_mode else v.tobytes(),
5412 optional=self.optional,
5413 _decoded=(offset, 0, tlvlen),
5415 obj.tag = t.tobytes()
5416 yield decode_path, obj, tail
5419 return pp_console_row(next(self.pps()))
5421 def pps(self, decode_path=()):
5425 elif value.__class__ == binary_type:
5431 asn1_type_name=self.asn1_type_name,
5432 obj_name=self.__class__.__name__,
5433 decode_path=decode_path,
5435 blob=self._value if self._value.__class__ == binary_type else None,
5436 optional=self.optional,
5437 default=self == self.default,
5438 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5439 expl=None if self._expl is None else tag_decode(self._expl),
5444 expl_offset=self.expl_offset if self.expled else None,
5445 expl_tlen=self.expl_tlen if self.expled else None,
5446 expl_llen=self.expl_llen if self.expled else None,
5447 expl_vlen=self.expl_vlen if self.expled else None,
5448 expl_lenindef=self.expl_lenindef,
5449 lenindef=self.lenindef,
5452 defined_by, defined = self.defined or (None, None)
5453 if defined_by is not None:
5455 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5457 for pp in self.pps_lenindef(decode_path):
5461 ########################################################################
5462 # ASN.1 constructed types
5463 ########################################################################
5465 def get_def_by_path(defines_by_path, sub_decode_path):
5466 """Get define by decode path
5468 for path, define in defines_by_path:
5469 if len(path) != len(sub_decode_path):
5471 for p1, p2 in zip(path, sub_decode_path):
5472 if (not p1 is any) and (p1 != p2):
5478 def abs_decode_path(decode_path, rel_path):
5479 """Create an absolute decode path from current and relative ones
5481 :param decode_path: current decode path, starting point. Tuple of strings
5482 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5483 If first tuple's element is "/", then treat it as
5484 an absolute path, ignoring ``decode_path`` as
5485 starting point. Also this tuple can contain ".."
5486 elements, stripping the leading element from
5489 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5490 ("foo", "bar", "baz", "whatever")
5491 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5493 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5496 if rel_path[0] == "/":
5498 if rel_path[0] == "..":
5499 return abs_decode_path(decode_path[:-1], rel_path[1:])
5500 return decode_path + rel_path
5503 SequenceState = namedtuple(
5505 BasicState._fields + ("specs", "value",),
5510 class Sequence(Obj):
5511 """``SEQUENCE`` structure type
5513 You have to make specification of sequence::
5515 class Extension(Sequence):
5517 ("extnID", ObjectIdentifier()),
5518 ("critical", Boolean(default=False)),
5519 ("extnValue", OctetString()),
5522 Then, you can work with it as with dictionary.
5524 >>> ext = Extension()
5525 >>> Extension().specs
5527 ('extnID', OBJECT IDENTIFIER),
5528 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5529 ('extnValue', OCTET STRING),
5531 >>> ext["extnID"] = "1.2.3"
5532 Traceback (most recent call last):
5533 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5534 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5536 You can determine if sequence is ready to be encoded:
5541 Traceback (most recent call last):
5542 pyderasn.ObjNotReady: object is not ready: extnValue
5543 >>> ext["extnValue"] = OctetString(b"foobar")
5547 Value you want to assign, must have the same **type** as in
5548 corresponding specification, but it can have different tags,
5549 optional/default attributes -- they will be taken from specification
5552 class TBSCertificate(Sequence):
5554 ("version", Version(expl=tag_ctxc(0), default="v1")),
5557 >>> tbs = TBSCertificate()
5558 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5560 Assign ``None`` to remove value from sequence.
5562 You can set values in Sequence during its initialization:
5564 >>> AlgorithmIdentifier((
5565 ("algorithm", ObjectIdentifier("1.2.3")),
5566 ("parameters", Any(Null()))
5568 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5570 You can determine if value exists/set in the sequence and take its value:
5572 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5575 OBJECT IDENTIFIER 1.2.3
5577 But pay attention that if value has default, then it won't be (not
5578 in) in the sequence (because ``DEFAULT`` must not be encoded in
5579 DER), but you can read its value:
5581 >>> "critical" in ext, ext["critical"]
5582 (False, BOOLEAN False)
5583 >>> ext["critical"] = Boolean(True)
5584 >>> "critical" in ext, ext["critical"]
5585 (True, BOOLEAN True)
5587 All defaulted values are always optional.
5589 .. _allow_default_values_ctx:
5591 DER prohibits default value encoding and will raise an error if
5592 default value is unexpectedly met during decode.
5593 If :ref:`bered <bered_ctx>` context option is set, then no error
5594 will be raised, but ``bered`` attribute set. You can disable strict
5595 defaulted values existence validation by setting
5596 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5600 Check for default value existence is not performed in
5601 ``evgen_mode``, because previously decoded values are not stored
5602 in memory, to be able to compare them.
5604 Two sequences are equal if they have equal specification (schema),
5605 implicit/explicit tagging and the same values.
5607 __slots__ = ("specs",)
5608 tag_default = tag_encode(form=TagFormConstructed, num=16)
5609 asn1_type_name = "SEQUENCE"
5621 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5623 schema = getattr(self, "schema", ())
5625 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
5628 if value is not None:
5629 if issubclass(value.__class__, Sequence):
5630 self._value = value._value
5631 elif hasattr(value, "__iter__"):
5632 for seq_key, seq_value in value:
5633 self[seq_key] = seq_value
5635 raise InvalidValueType((Sequence,))
5636 if default is not None:
5637 if not issubclass(default.__class__, Sequence):
5638 raise InvalidValueType((Sequence,))
5639 default_value = default._value
5640 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5641 default_obj.specs = self.specs
5642 default_obj._value = default_value
5643 self.default = default_obj
5645 self._value = copy(default_obj._value)
5649 for name, spec in iteritems(self.specs):
5650 value = self._value.get(name)
5661 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5663 return any(value.bered for value in itervalues(self._value))
5665 def __getstate__(self):
5666 return SequenceState(
5680 {k: copy(v) for k, v in iteritems(self._value)},
5683 def __setstate__(self, state):
5684 super(Sequence, self).__setstate__(state)
5685 self.specs = state.specs
5686 self._value = state.value
5688 def __eq__(self, their):
5689 if not isinstance(their, self.__class__):
5692 self.specs == their.specs and
5693 self.tag == their.tag and
5694 self._expl == their._expl and
5695 self._value == their._value
5706 return self.__class__(
5709 impl=self.tag if impl is None else impl,
5710 expl=self._expl if expl is None else expl,
5711 default=self.default if default is None else default,
5712 optional=self.optional if optional is None else optional,
5715 def __contains__(self, key):
5716 return key in self._value
5718 def __setitem__(self, key, value):
5719 spec = self.specs.get(key)
5721 raise ObjUnknown(key)
5723 self._value.pop(key, None)
5725 if not isinstance(value, spec.__class__):
5726 raise InvalidValueType((spec.__class__,))
5727 value = spec(value=value)
5728 if spec.default is not None and value == spec.default:
5729 self._value.pop(key, None)
5731 self._value[key] = value
5733 def __getitem__(self, key):
5734 value = self._value.get(key)
5735 if value is not None:
5737 spec = self.specs.get(key)
5739 raise ObjUnknown(key)
5740 if spec.default is not None:
5744 def _values_for_encoding(self):
5745 for name, spec in iteritems(self.specs):
5746 value = self._value.get(name)
5750 raise ObjNotReady(name)
5754 v = b"".join(v.encode() for v in self._values_for_encoding())
5755 return b"".join((self.tag, len_encode(len(v)), v))
5757 def _encode_cer(self, writer):
5758 write_full(writer, self.tag + LENINDEF)
5759 for v in self._values_for_encoding():
5760 v.encode_cer(writer)
5761 write_full(writer, EOC)
5763 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5765 t, tlen, lv = tag_strip(tlv)
5766 except DecodeError as err:
5767 raise err.__class__(
5769 klass=self.__class__,
5770 decode_path=decode_path,
5775 klass=self.__class__,
5776 decode_path=decode_path,
5779 if tag_only: # pragma: no cover
5783 ctx_bered = ctx.get("bered", False)
5785 l, llen, v = len_decode(lv)
5786 except LenIndefForm as err:
5788 raise err.__class__(
5790 klass=self.__class__,
5791 decode_path=decode_path,
5794 l, llen, v = 0, 1, lv[1:]
5796 except DecodeError as err:
5797 raise err.__class__(
5799 klass=self.__class__,
5800 decode_path=decode_path,
5804 raise NotEnoughData(
5805 "encoded length is longer than data",
5806 klass=self.__class__,
5807 decode_path=decode_path,
5811 v, tail = v[:l], v[l:]
5813 sub_offset = offset + tlen + llen
5816 ctx_allow_default_values = ctx.get("allow_default_values", False)
5817 for name, spec in iteritems(self.specs):
5818 if spec.optional and (
5819 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5823 sub_decode_path = decode_path + (name,)
5826 for _decode_path, value, v_tail in spec.decode_evgen(
5830 decode_path=sub_decode_path,
5832 _ctx_immutable=False,
5834 yield _decode_path, value, v_tail
5836 _, value, v_tail = next(spec.decode_evgen(
5840 decode_path=sub_decode_path,
5842 _ctx_immutable=False,
5845 except TagMismatch as err:
5846 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5850 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5851 if not evgen_mode and defined is not None:
5852 defined_by, defined_spec = defined
5853 if issubclass(value.__class__, SequenceOf):
5854 for i, _value in enumerate(value):
5855 sub_sub_decode_path = sub_decode_path + (
5857 DecodePathDefBy(defined_by),
5859 defined_value, defined_tail = defined_spec.decode(
5860 memoryview(bytes(_value)),
5862 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5863 if value.expled else (value.tlen + value.llen)
5866 decode_path=sub_sub_decode_path,
5868 _ctx_immutable=False,
5870 if len(defined_tail) > 0:
5873 klass=self.__class__,
5874 decode_path=sub_sub_decode_path,
5877 _value.defined = (defined_by, defined_value)
5879 defined_value, defined_tail = defined_spec.decode(
5880 memoryview(bytes(value)),
5882 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5883 if value.expled else (value.tlen + value.llen)
5886 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5888 _ctx_immutable=False,
5890 if len(defined_tail) > 0:
5893 klass=self.__class__,
5894 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5897 value.defined = (defined_by, defined_value)
5899 value_len = value.fulllen
5901 sub_offset += value_len
5904 if spec.default is not None and value == spec.default:
5905 # This will not work in evgen_mode
5906 if ctx_bered or ctx_allow_default_values:
5910 "DEFAULT value met",
5911 klass=self.__class__,
5912 decode_path=sub_decode_path,
5915 values[name] = value
5916 spec_defines = getattr(spec, "defines", ())
5917 if len(spec_defines) == 0:
5918 defines_by_path = ctx.get("defines_by_path", ())
5919 if len(defines_by_path) > 0:
5920 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5921 if spec_defines is not None and len(spec_defines) > 0:
5922 for rel_path, schema in spec_defines:
5923 defined = schema.get(value, None)
5924 if defined is not None:
5925 ctx.setdefault("_defines", []).append((
5926 abs_decode_path(sub_decode_path[:-1], rel_path),
5930 if v[:EOC_LEN].tobytes() != EOC:
5933 klass=self.__class__,
5934 decode_path=decode_path,
5942 klass=self.__class__,
5943 decode_path=decode_path,
5946 obj = self.__class__(
5950 default=self.default,
5951 optional=self.optional,
5952 _decoded=(offset, llen, vlen),
5955 obj.lenindef = lenindef
5956 obj.ber_encoded = ber_encoded
5957 yield decode_path, obj, tail
5960 value = pp_console_row(next(self.pps()))
5962 for name in self.specs:
5963 _value = self._value.get(name)
5966 cols.append("%s: %s" % (name, repr(_value)))
5967 return "%s[%s]" % (value, "; ".join(cols))
5969 def pps(self, decode_path=()):
5972 asn1_type_name=self.asn1_type_name,
5973 obj_name=self.__class__.__name__,
5974 decode_path=decode_path,
5975 optional=self.optional,
5976 default=self == self.default,
5977 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5978 expl=None if self._expl is None else tag_decode(self._expl),
5983 expl_offset=self.expl_offset if self.expled else None,
5984 expl_tlen=self.expl_tlen if self.expled else None,
5985 expl_llen=self.expl_llen if self.expled else None,
5986 expl_vlen=self.expl_vlen if self.expled else None,
5987 expl_lenindef=self.expl_lenindef,
5988 lenindef=self.lenindef,
5989 ber_encoded=self.ber_encoded,
5992 for name in self.specs:
5993 value = self._value.get(name)
5996 yield value.pps(decode_path=decode_path + (name,))
5997 for pp in self.pps_lenindef(decode_path):
6001 class Set(Sequence):
6002 """``SET`` structure type
6004 Its usage is identical to :py:class:`pyderasn.Sequence`.
6006 .. _allow_unordered_set_ctx:
6008 DER prohibits unordered values encoding and will raise an error
6009 during decode. If :ref:`bered <bered_ctx>` context option is set,
6010 then no error will occur. Also you can disable strict values
6011 ordering check by setting ``"allow_unordered_set": True``
6012 :ref:`context <ctx>` option.
6015 tag_default = tag_encode(form=TagFormConstructed, num=17)
6016 asn1_type_name = "SET"
6019 v = b"".join(value.encode() for value in sorted(
6020 self._values_for_encoding(),
6021 key=attrgetter("tag_order"),
6023 return b"".join((self.tag, len_encode(len(v)), v))
6025 def _encode_cer(self, writer):
6026 write_full(writer, self.tag + LENINDEF)
6028 self._values_for_encoding(),
6029 key=attrgetter("tag_order_cer"),
6031 v.encode_cer(writer)
6032 write_full(writer, EOC)
6034 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
6036 t, tlen, lv = tag_strip(tlv)
6037 except DecodeError as err:
6038 raise err.__class__(
6040 klass=self.__class__,
6041 decode_path=decode_path,
6046 klass=self.__class__,
6047 decode_path=decode_path,
6054 ctx_bered = ctx.get("bered", False)
6056 l, llen, v = len_decode(lv)
6057 except LenIndefForm as err:
6059 raise err.__class__(
6061 klass=self.__class__,
6062 decode_path=decode_path,
6065 l, llen, v = 0, 1, lv[1:]
6067 except DecodeError as err:
6068 raise err.__class__(
6070 klass=self.__class__,
6071 decode_path=decode_path,
6075 raise NotEnoughData(
6076 "encoded length is longer than data",
6077 klass=self.__class__,
6081 v, tail = v[:l], v[l:]
6083 sub_offset = offset + tlen + llen
6086 ctx_allow_default_values = ctx.get("allow_default_values", False)
6087 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6088 tag_order_prev = (0, 0)
6089 _specs_items = copy(self.specs)
6092 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6094 for name, spec in iteritems(_specs_items):
6095 sub_decode_path = decode_path + (name,)
6101 decode_path=sub_decode_path,
6104 _ctx_immutable=False,
6111 klass=self.__class__,
6112 decode_path=decode_path,
6116 for _decode_path, value, v_tail in spec.decode_evgen(
6120 decode_path=sub_decode_path,
6122 _ctx_immutable=False,
6124 yield _decode_path, value, v_tail
6126 _, value, v_tail = next(spec.decode_evgen(
6130 decode_path=sub_decode_path,
6132 _ctx_immutable=False,
6135 value_tag_order = value.tag_order
6136 value_len = value.fulllen
6137 if tag_order_prev >= value_tag_order:
6138 if ctx_bered or ctx_allow_unordered_set:
6142 "unordered " + self.asn1_type_name,
6143 klass=self.__class__,
6144 decode_path=sub_decode_path,
6147 if spec.default is None or value != spec.default:
6149 elif ctx_bered or ctx_allow_default_values:
6153 "DEFAULT value met",
6154 klass=self.__class__,
6155 decode_path=sub_decode_path,
6158 values[name] = value
6159 del _specs_items[name]
6160 tag_order_prev = value_tag_order
6161 sub_offset += value_len
6165 obj = self.__class__(
6169 default=self.default,
6170 optional=self.optional,
6171 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6174 if v[:EOC_LEN].tobytes() != EOC:
6177 klass=self.__class__,
6178 decode_path=decode_path,
6183 for name, spec in iteritems(self.specs):
6184 if name not in values and not spec.optional:
6186 "%s value is not ready" % name,
6187 klass=self.__class__,
6188 decode_path=decode_path,
6193 obj.ber_encoded = ber_encoded
6194 yield decode_path, obj, tail
6197 SequenceOfState = namedtuple(
6199 BasicState._fields + ("spec", "value", "bound_min", "bound_max"),
6204 class SequenceOf(Obj):
6205 """``SEQUENCE OF`` sequence type
6207 For that kind of type you must specify the object it will carry on
6208 (bounds are for example here, not required)::
6210 class Ints(SequenceOf):
6215 >>> ints.append(Integer(123))
6216 >>> ints.append(Integer(234))
6218 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
6219 >>> [int(i) for i in ints]
6221 >>> ints.append(Integer(345))
6222 Traceback (most recent call last):
6223 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
6226 >>> ints[1] = Integer(345)
6228 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
6230 You can initialize sequence with preinitialized values:
6232 >>> ints = Ints([Integer(123), Integer(234)])
6234 Also you can use iterator as a value:
6236 >>> ints = Ints(iter(Integer(i) for i in range(1000000)))
6238 And it won't be iterated until encoding process. Pay attention that
6239 bounds and required schema checks are done only during the encoding
6240 process in that case! After encode was called, then value is zeroed
6241 back to empty list and you have to set it again. That mode is useful
6242 mainly with CER encoding mode, where all objects from the iterable
6243 will be streamed to the buffer, without copying all of them to
6246 __slots__ = ("spec", "_bound_min", "_bound_max")
6247 tag_default = tag_encode(form=TagFormConstructed, num=16)
6248 asn1_type_name = "SEQUENCE OF"
6261 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
6263 schema = getattr(self, "schema", None)
6265 raise ValueError("schema must be specified")
6267 self._bound_min, self._bound_max = getattr(
6271 ) if bounds is None else bounds
6273 if value is not None:
6274 self._value = self._value_sanitize(value)
6275 if default is not None:
6276 default_value = self._value_sanitize(default)
6277 default_obj = self.__class__(
6282 default_obj._value = default_value
6283 self.default = default_obj
6285 self._value = copy(default_obj._value)
6287 def _value_sanitize(self, value):
6289 if issubclass(value.__class__, SequenceOf):
6290 value = value._value
6291 elif hasattr(value, NEXT_ATTR_NAME):
6294 elif hasattr(value, "__iter__"):
6297 raise InvalidValueType((self.__class__, iter, "iterator"))
6299 if not self._bound_min <= len(value) <= self._bound_max:
6300 raise BoundsError(self._bound_min, len(value), self._bound_max)
6301 class_expected = self.spec.__class__
6303 if not isinstance(v, class_expected):
6304 raise InvalidValueType((class_expected,))
6309 if hasattr(self._value, NEXT_ATTR_NAME):
6311 if self._bound_min > 0 and len(self._value) == 0:
6313 return all(v.ready for v in self._value)
6317 if self.expl_lenindef or self.lenindef or self.ber_encoded:
6319 return any(v.bered for v in self._value)
6321 def __getstate__(self):
6322 if hasattr(self._value, NEXT_ATTR_NAME):
6323 raise ValueError("can not pickle SequenceOf with iterator")
6324 return SequenceOfState(
6338 [copy(v) for v in self._value],
6343 def __setstate__(self, state):
6344 super(SequenceOf, self).__setstate__(state)
6345 self.spec = state.spec
6346 self._value = state.value
6347 self._bound_min = state.bound_min
6348 self._bound_max = state.bound_max
6350 def __eq__(self, their):
6351 if isinstance(their, self.__class__):
6353 self.spec == their.spec and
6354 self.tag == their.tag and
6355 self._expl == their._expl and
6356 self._value == their._value
6358 if hasattr(their, "__iter__"):
6359 return self._value == list(their)
6371 return self.__class__(
6375 (self._bound_min, self._bound_max)
6376 if bounds is None else bounds
6378 impl=self.tag if impl is None else impl,
6379 expl=self._expl if expl is None else expl,
6380 default=self.default if default is None else default,
6381 optional=self.optional if optional is None else optional,
6384 def __contains__(self, key):
6385 return key in self._value
6387 def append(self, value):
6388 if not isinstance(value, self.spec.__class__):
6389 raise InvalidValueType((self.spec.__class__,))
6390 if len(self._value) + 1 > self._bound_max:
6393 len(self._value) + 1,
6396 self._value.append(value)
6399 return iter(self._value)
6402 return len(self._value)
6404 def __setitem__(self, key, value):
6405 if not isinstance(value, self.spec.__class__):
6406 raise InvalidValueType((self.spec.__class__,))
6407 self._value[key] = self.spec(value=value)
6409 def __getitem__(self, key):
6410 return self._value[key]
6412 def _values_for_encoding(self):
6413 return iter(self._value)
6416 iterator = hasattr(self._value, NEXT_ATTR_NAME)
6419 values_append = values.append
6420 class_expected = self.spec.__class__
6421 values_for_encoding = self._values_for_encoding()
6423 for v in values_for_encoding:
6424 if not isinstance(v, class_expected):
6425 raise InvalidValueType((class_expected,))
6426 values_append(v.encode())
6427 if not self._bound_min <= len(values) <= self._bound_max:
6428 raise BoundsError(self._bound_min, len(values), self._bound_max)
6429 value = b"".join(values)
6431 value = b"".join(v.encode() for v in self._values_for_encoding())
6432 return b"".join((self.tag, len_encode(len(value)), value))
6434 def _encode_cer(self, writer):
6435 write_full(writer, self.tag + LENINDEF)
6436 iterator = hasattr(self._value, NEXT_ATTR_NAME)
6438 class_expected = self.spec.__class__
6440 values_for_encoding = self._values_for_encoding()
6442 for v in values_for_encoding:
6443 if not isinstance(v, class_expected):
6444 raise InvalidValueType((class_expected,))
6445 v.encode_cer(writer)
6447 if not self._bound_min <= values_count <= self._bound_max:
6448 raise BoundsError(self._bound_min, values_count, self._bound_max)
6450 for v in self._values_for_encoding():
6451 v.encode_cer(writer)
6452 write_full(writer, EOC)
6462 ordering_check=False,
6465 t, tlen, lv = tag_strip(tlv)
6466 except DecodeError as err:
6467 raise err.__class__(
6469 klass=self.__class__,
6470 decode_path=decode_path,
6475 klass=self.__class__,
6476 decode_path=decode_path,
6483 ctx_bered = ctx.get("bered", False)
6485 l, llen, v = len_decode(lv)
6486 except LenIndefForm as err:
6488 raise err.__class__(
6490 klass=self.__class__,
6491 decode_path=decode_path,
6494 l, llen, v = 0, 1, lv[1:]
6496 except DecodeError as err:
6497 raise err.__class__(
6499 klass=self.__class__,
6500 decode_path=decode_path,
6504 raise NotEnoughData(
6505 "encoded length is longer than data",
6506 klass=self.__class__,
6507 decode_path=decode_path,
6511 v, tail = v[:l], v[l:]
6513 sub_offset = offset + tlen + llen
6516 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6517 value_prev = memoryview(v[:0])
6521 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6523 sub_decode_path = decode_path + (str(_value_count),)
6525 for _decode_path, value, v_tail in spec.decode_evgen(
6529 decode_path=sub_decode_path,
6531 _ctx_immutable=False,
6533 yield _decode_path, value, v_tail
6535 _, value, v_tail = next(spec.decode_evgen(
6539 decode_path=sub_decode_path,
6541 _ctx_immutable=False,
6544 value_len = value.fulllen
6546 if value_prev.tobytes() > v[:value_len].tobytes():
6547 if ctx_bered or ctx_allow_unordered_set:
6551 "unordered " + self.asn1_type_name,
6552 klass=self.__class__,
6553 decode_path=sub_decode_path,
6556 value_prev = v[:value_len]
6559 _value.append(value)
6560 sub_offset += value_len
6563 if evgen_mode and not self._bound_min <= _value_count <= self._bound_max:
6565 msg=str(BoundsError(self._bound_min, _value_count, self._bound_max)),
6566 klass=self.__class__,
6567 decode_path=decode_path,
6571 obj = self.__class__(
6572 value=None if evgen_mode else _value,
6574 bounds=(self._bound_min, self._bound_max),
6577 default=self.default,
6578 optional=self.optional,
6579 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6581 except BoundsError as err:
6584 klass=self.__class__,
6585 decode_path=decode_path,
6589 if v[:EOC_LEN].tobytes() != EOC:
6592 klass=self.__class__,
6593 decode_path=decode_path,
6598 obj.ber_encoded = ber_encoded
6599 yield decode_path, obj, tail
6603 pp_console_row(next(self.pps())),
6604 ", ".join(repr(v) for v in self._value),
6607 def pps(self, decode_path=()):
6610 asn1_type_name=self.asn1_type_name,
6611 obj_name=self.__class__.__name__,
6612 decode_path=decode_path,
6613 optional=self.optional,
6614 default=self == self.default,
6615 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6616 expl=None if self._expl is None else tag_decode(self._expl),
6621 expl_offset=self.expl_offset if self.expled else None,
6622 expl_tlen=self.expl_tlen if self.expled else None,
6623 expl_llen=self.expl_llen if self.expled else None,
6624 expl_vlen=self.expl_vlen if self.expled else None,
6625 expl_lenindef=self.expl_lenindef,
6626 lenindef=self.lenindef,
6627 ber_encoded=self.ber_encoded,
6630 for i, value in enumerate(self._value):
6631 yield value.pps(decode_path=decode_path + (str(i),))
6632 for pp in self.pps_lenindef(decode_path):
6636 class SetOf(SequenceOf):
6637 """``SET OF`` sequence type
6639 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6642 tag_default = tag_encode(form=TagFormConstructed, num=17)
6643 asn1_type_name = "SET OF"
6645 def _value_sanitize(self, value):
6646 value = super(SetOf, self)._value_sanitize(value)
6647 if hasattr(value, NEXT_ATTR_NAME):
6649 "SetOf does not support iterator values, as no sense in them"
6654 v = b"".join(sorted(v.encode() for v in self._values_for_encoding()))
6655 return b"".join((self.tag, len_encode(len(v)), v))
6657 def _encode_cer(self, writer):
6658 write_full(writer, self.tag + LENINDEF)
6659 for v in sorted(encode_cer(v) for v in self._values_for_encoding()):
6660 write_full(writer, v)
6661 write_full(writer, EOC)
6663 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
6664 return super(SetOf, self)._decode(
6671 ordering_check=True,
6675 def obj_by_path(pypath): # pragma: no cover
6676 """Import object specified as string Python path
6678 Modules must be separated from classes/functions with ``:``.
6680 >>> obj_by_path("foo.bar:Baz")
6681 <class 'foo.bar.Baz'>
6682 >>> obj_by_path("foo.bar:Baz.boo")
6683 <classmethod 'foo.bar.Baz.boo'>
6685 mod, objs = pypath.rsplit(":", 1)
6686 from importlib import import_module
6687 obj = import_module(mod)
6688 for obj_name in objs.split("."):
6689 obj = getattr(obj, obj_name)
6693 def generic_decoder(): # pragma: no cover
6694 # All of this below is a big hack with self references
6695 choice = PrimitiveTypes()
6696 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6697 choice.specs["SetOf"] = SetOf(schema=choice)
6698 for i in six_xrange(31):
6699 choice.specs["SequenceOf%d" % i] = SequenceOf(
6703 choice.specs["Any"] = Any()
6705 # Class name equals to type name, to omit it from output
6706 class SEQUENCEOF(SequenceOf):
6714 with_decode_path=False,
6715 decode_path_only=(),
6717 def _pprint_pps(pps):
6719 if hasattr(pp, "_fields"):
6721 decode_path_only != () and
6722 pp.decode_path[:len(decode_path_only)] != decode_path_only
6725 if pp.asn1_type_name == Choice.asn1_type_name:
6727 pp_kwargs = pp._asdict()
6728 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6729 pp = _pp(**pp_kwargs)
6730 yield pp_console_row(
6735 with_colours=with_colours,
6736 with_decode_path=with_decode_path,
6737 decode_path_len_decrease=len(decode_path_only),
6739 for row in pp_console_blob(
6741 decode_path_len_decrease=len(decode_path_only),
6745 for row in _pprint_pps(pp):
6747 return "\n".join(_pprint_pps(obj.pps()))
6748 return SEQUENCEOF(), pprint_any
6751 def main(): # pragma: no cover
6753 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6754 parser.add_argument(
6758 help="Skip that number of bytes from the beginning",
6760 parser.add_argument(
6762 help="Python paths to dictionary with OIDs, comma separated",
6764 parser.add_argument(
6766 help="Python path to schema definition to use",
6768 parser.add_argument(
6769 "--defines-by-path",
6770 help="Python path to decoder's defines_by_path",
6772 parser.add_argument(
6774 action="store_true",
6775 help="Disallow BER encoding",
6777 parser.add_argument(
6778 "--print-decode-path",
6779 action="store_true",
6780 help="Print decode paths",
6782 parser.add_argument(
6783 "--decode-path-only",
6784 help="Print only specified decode path",
6786 parser.add_argument(
6788 action="store_true",
6789 help="Allow explicit tag out-of-bound",
6791 parser.add_argument(
6793 action="store_true",
6794 help="Turn on event generation mode",
6796 parser.add_argument(
6798 type=argparse.FileType("rb"),
6799 help="Path to BER/CER/DER file you want to decode",
6801 args = parser.parse_args()
6803 args.RAWFile.seek(args.skip)
6804 raw = memoryview(args.RAWFile.read())
6805 args.RAWFile.close()
6807 raw = file_mmaped(args.RAWFile)[args.skip:]
6809 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6810 if args.oids else ()
6813 schema = obj_by_path(args.schema)
6814 from functools import partial
6815 pprinter = partial(pprint, big_blobs=True)
6817 schema, pprinter = generic_decoder()
6819 "bered": not args.nobered,
6820 "allow_expl_oob": args.allow_expl_oob,
6822 if args.defines_by_path is not None:
6823 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6824 from os import environ
6828 with_colours=environ.get("NO_COLOR") is None,
6829 with_decode_path=args.print_decode_path,
6831 () if args.decode_path_only is None else
6832 tuple(args.decode_path_only.split(":"))
6836 for decode_path, obj, tail in schema().decode_evgen(raw, ctx=ctx):
6837 print(pprinter(obj, decode_path=decode_path))
6839 obj, tail = schema().decode(raw, ctx=ctx)
6840 print(pprinter(obj))
6842 print("\nTrailing data: %s" % hexenc(tail))
6845 if __name__ == "__main__":