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)
900 """Make mmap-ed memoryview for reading from file
902 :param fd: file object
903 :returns: memoryview over read-only mmap-ing of the whole file
905 return memoryview(mmap(fd.fileno(), 0, prot=PROT_READ))
908 if not set(value) <= DECIMALS:
909 raise ValueError("non-pure integer")
912 def fractions2float(fractions_raw):
913 pureint(fractions_raw)
914 return float("0." + fractions_raw)
917 def get_def_by_path(defines_by_path, sub_decode_path):
918 """Get define by decode path
920 for path, define in defines_by_path:
921 if len(path) != len(sub_decode_path):
923 for p1, p2 in zip(path, sub_decode_path):
924 if (not p1 is any) and (p1 != p2):
930 ########################################################################
932 ########################################################################
934 class ASN1Error(ValueError):
938 class DecodeError(ASN1Error):
939 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
941 :param str msg: reason of decode failing
942 :param klass: optional exact DecodeError inherited class (like
943 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
944 :py:exc:`InvalidLength`)
945 :param decode_path: tuple of strings. It contains human
946 readable names of the fields through which
947 decoding process has passed
948 :param int offset: binary offset where failure happened
950 super(DecodeError, self).__init__()
953 self.decode_path = decode_path
959 "" if self.klass is None else self.klass.__name__,
961 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
962 if len(self.decode_path) > 0 else ""
964 ("(at %d)" % self.offset) if self.offset > 0 else "",
970 return "%s(%s)" % (self.__class__.__name__, self)
973 class NotEnoughData(DecodeError):
977 class ExceedingData(ASN1Error):
978 def __init__(self, nbytes):
979 super(ExceedingData, self).__init__()
983 return "%d trailing bytes" % self.nbytes
986 return "%s(%s)" % (self.__class__.__name__, self)
989 class LenIndefForm(DecodeError):
993 class TagMismatch(DecodeError):
997 class InvalidLength(DecodeError):
1001 class InvalidOID(DecodeError):
1005 class ObjUnknown(ASN1Error):
1006 def __init__(self, name):
1007 super(ObjUnknown, self).__init__()
1011 return "object is unknown: %s" % self.name
1014 return "%s(%s)" % (self.__class__.__name__, self)
1017 class ObjNotReady(ASN1Error):
1018 def __init__(self, name):
1019 super(ObjNotReady, self).__init__()
1023 return "object is not ready: %s" % self.name
1026 return "%s(%s)" % (self.__class__.__name__, self)
1029 class InvalidValueType(ASN1Error):
1030 def __init__(self, expected_types):
1031 super(InvalidValueType, self).__init__()
1032 self.expected_types = expected_types
1035 return "invalid value type, expected: %s" % ", ".join(
1036 [repr(t) for t in self.expected_types]
1040 return "%s(%s)" % (self.__class__.__name__, self)
1043 class BoundsError(ASN1Error):
1044 def __init__(self, bound_min, value, bound_max):
1045 super(BoundsError, self).__init__()
1046 self.bound_min = bound_min
1048 self.bound_max = bound_max
1051 return "unsatisfied bounds: %s <= %s <= %s" % (
1058 return "%s(%s)" % (self.__class__.__name__, self)
1061 ########################################################################
1063 ########################################################################
1065 _hexdecoder = getdecoder("hex")
1066 _hexencoder = getencoder("hex")
1070 """Binary data to hexadecimal string convert
1072 return _hexdecoder(data)[0]
1076 """Hexadecimal string to binary data convert
1078 return _hexencoder(data)[0].decode("ascii")
1081 def int_bytes_len(num, byte_len=8):
1084 return int(ceil(float(num.bit_length()) / byte_len))
1087 def zero_ended_encode(num):
1088 octets = bytearray(int_bytes_len(num, 7))
1090 octets[i] = num & 0x7F
1094 octets[i] = 0x80 | (num & 0x7F)
1097 return bytes(octets)
1100 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
1101 """Encode tag to binary form
1103 :param int num: tag's number
1104 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
1105 :py:data:`pyderasn.TagClassContext`,
1106 :py:data:`pyderasn.TagClassApplication`,
1107 :py:data:`pyderasn.TagClassPrivate`)
1108 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
1109 :py:data:`pyderasn.TagFormConstructed`)
1113 return int2byte(klass | form | num)
1114 # [XX|X|11111][1.......][1.......] ... [0.......]
1115 return int2byte(klass | form | 31) + zero_ended_encode(num)
1118 def tag_decode(tag):
1119 """Decode tag from binary form
1123 No validation is performed, assuming that it has already passed.
1125 It returns tuple with three integers, as
1126 :py:func:`pyderasn.tag_encode` accepts.
1128 first_octet = byte2int(tag)
1129 klass = first_octet & 0xC0
1130 form = first_octet & 0x20
1131 if first_octet & 0x1F < 0x1F:
1132 return (klass, form, first_octet & 0x1F)
1134 for octet in iterbytes(tag[1:]):
1137 return (klass, form, num)
1141 """Create CONTEXT PRIMITIVE tag
1143 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
1147 """Create CONTEXT CONSTRUCTED tag
1149 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
1152 def tag_strip(data):
1153 """Take off tag from the data
1155 :returns: (encoded tag, tag length, remaining data)
1158 raise NotEnoughData("no data at all")
1159 if byte2int(data) & 0x1F < 31:
1160 return data[:1], 1, data[1:]
1165 raise DecodeError("unfinished tag")
1166 if indexbytes(data, i) & 0x80 == 0:
1169 return data[:i], i, data[i:]
1175 octets = bytearray(int_bytes_len(l) + 1)
1176 octets[0] = 0x80 | (len(octets) - 1)
1177 for i in six_xrange(len(octets) - 1, 0, -1):
1178 octets[i] = l & 0xFF
1180 return bytes(octets)
1183 def len_decode(data):
1186 :returns: (decoded length, length's length, remaining data)
1187 :raises LenIndefForm: if indefinite form encoding is met
1190 raise NotEnoughData("no data at all")
1191 first_octet = byte2int(data)
1192 if first_octet & 0x80 == 0:
1193 return first_octet, 1, data[1:]
1194 octets_num = first_octet & 0x7F
1195 if octets_num + 1 > len(data):
1196 raise NotEnoughData("encoded length is longer than data")
1198 raise LenIndefForm()
1199 if byte2int(data[1:]) == 0:
1200 raise DecodeError("leading zeros")
1202 for v in iterbytes(data[1:1 + octets_num]):
1205 raise DecodeError("long form instead of short one")
1206 return l, 1 + octets_num, data[1 + octets_num:]
1209 LEN1K = len_encode(1000)
1212 def write_full(writer, data):
1213 """Fully write provided data
1215 BytesIO does not guarantee that the whole data will be written at once.
1217 data = memoryview(data)
1219 while written != len(data):
1220 n = writer(data[written:])
1222 raise ValueError("can not write to buf")
1226 ########################################################################
1228 ########################################################################
1230 class AutoAddSlots(type):
1231 def __new__(cls, name, bases, _dict):
1232 _dict["__slots__"] = _dict.get("__slots__", ())
1233 return type.__new__(cls, name, bases, _dict)
1236 BasicState = namedtuple("BasicState", (
1249 ), **NAMEDTUPLE_KWARGS)
1252 @add_metaclass(AutoAddSlots)
1254 """Common ASN.1 object class
1256 All ASN.1 types are inherited from it. It has metaclass that
1257 automatically adds ``__slots__`` to all inherited classes.
1282 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1283 self._expl = getattr(self, "expl", None) if expl is None else expl
1284 if self.tag != self.tag_default and self._expl is not None:
1285 raise ValueError("implicit and explicit tags can not be set simultaneously")
1286 if self.tag is None:
1287 self._tag_order = None
1289 tag_class, _, tag_num = tag_decode(
1290 self.tag if self._expl is None else self._expl
1292 self._tag_order = (tag_class, tag_num)
1293 if default is not None:
1295 self.optional = optional
1296 self.offset, self.llen, self.vlen = _decoded
1298 self.expl_lenindef = False
1299 self.lenindef = False
1300 self.ber_encoded = False
1303 def ready(self): # pragma: no cover
1304 """Is object ready to be encoded?
1306 raise NotImplementedError()
1308 def _assert_ready(self):
1310 raise ObjNotReady(self.__class__.__name__)
1314 """Is either object or any elements inside is BER encoded?
1316 return self.expl_lenindef or self.lenindef or self.ber_encoded
1320 """Is object decoded?
1322 return (self.llen + self.vlen) > 0
1324 def __getstate__(self): # pragma: no cover
1325 """Used for making safe to be mutable pickleable copies
1327 raise NotImplementedError()
1329 def __setstate__(self, state):
1330 if state.version != __version__:
1331 raise ValueError("data is pickled by different PyDERASN version")
1332 self.tag = state.tag
1333 self._tag_order = state.tag_order
1334 self._expl = state.expl
1335 self.default = state.default
1336 self.optional = state.optional
1337 self.offset = state.offset
1338 self.llen = state.llen
1339 self.vlen = state.vlen
1340 self.expl_lenindef = state.expl_lenindef
1341 self.lenindef = state.lenindef
1342 self.ber_encoded = state.ber_encoded
1345 def tag_order(self):
1346 """Tag's (class, number) used for DER/CER sorting
1348 return self._tag_order
1351 def tag_order_cer(self):
1352 return self.tag_order
1356 """See :ref:`decoding`
1358 return len(self.tag)
1362 """See :ref:`decoding`
1364 return self.tlen + self.llen + self.vlen
1366 def __str__(self): # pragma: no cover
1367 return self.__bytes__() if PY2 else self.__unicode__()
1369 def __ne__(self, their):
1370 return not(self == their)
1372 def __gt__(self, their): # pragma: no cover
1373 return not(self < their)
1375 def __le__(self, their): # pragma: no cover
1376 return (self == their) or (self < their)
1378 def __ge__(self, their): # pragma: no cover
1379 return (self == their) or (self > their)
1381 def _encode(self): # pragma: no cover
1382 raise NotImplementedError()
1384 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode): # pragma: no cover
1385 yield NotImplemented
1388 """Encode the structure
1390 :returns: DER representation
1392 raw = self._encode()
1393 if self._expl is None:
1395 return b"".join((self._expl, len_encode(len(raw)), raw))
1397 def encode_cer(self, writer):
1398 if self._expl is not None:
1399 write_full(writer, self._expl + LENINDEF)
1400 if getattr(self, "der_forced", False):
1401 write_full(writer, self._encode())
1403 self._encode_cer(writer)
1404 if self._expl is not None:
1405 write_full(writer, EOC)
1407 def _encode_cer(self, writer):
1408 write_full(writer, self._encode())
1410 def hexencode(self):
1411 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1413 return hexenc(self.encode())
1423 _ctx_immutable=True,
1425 result = next(self.decode_evgen(
1437 _, obj, tail = result
1448 _ctx_immutable=True,
1453 :param data: either binary or memoryview
1454 :param int offset: initial data's offset
1455 :param bool leavemm: do we need to leave memoryview of remaining
1456 data as is, or convert it to bytes otherwise
1457 :param ctx: optional :ref:`context <ctx>` governing decoding process
1458 :param tag_only: decode only the tag, without length and contents
1459 (used only in Choice and Set structures, trying to
1460 determine if tag satisfies the schema)
1461 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1463 :returns: (Obj, remaining data)
1465 .. seealso:: :ref:`decoding`
1469 elif _ctx_immutable:
1471 tlv = memoryview(data)
1474 get_def_by_path(ctx.get("evgen_mode_upto", ()), decode_path) is not None
1477 if self._expl is None:
1478 for result in self._decode(
1481 decode_path=decode_path,
1484 evgen_mode=_evgen_mode,
1489 _decode_path, obj, tail = result
1490 if not _decode_path is decode_path:
1494 t, tlen, lv = tag_strip(tlv)
1495 except DecodeError as err:
1496 raise err.__class__(
1498 klass=self.__class__,
1499 decode_path=decode_path,
1504 klass=self.__class__,
1505 decode_path=decode_path,
1509 l, llen, v = len_decode(lv)
1510 except LenIndefForm as err:
1511 if not ctx.get("bered", False):
1512 raise err.__class__(
1514 klass=self.__class__,
1515 decode_path=decode_path,
1519 offset += tlen + llen
1520 for result in self._decode(
1523 decode_path=decode_path,
1526 evgen_mode=_evgen_mode,
1528 if tag_only: # pragma: no cover
1531 _decode_path, obj, tail = result
1532 if not _decode_path is decode_path:
1534 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1535 if eoc_expected.tobytes() != EOC:
1538 klass=self.__class__,
1539 decode_path=decode_path,
1543 obj.expl_lenindef = True
1544 except DecodeError as err:
1545 raise err.__class__(
1547 klass=self.__class__,
1548 decode_path=decode_path,
1553 raise NotEnoughData(
1554 "encoded length is longer than data",
1555 klass=self.__class__,
1556 decode_path=decode_path,
1559 for result in self._decode(
1561 offset=offset + tlen + llen,
1562 decode_path=decode_path,
1565 evgen_mode=_evgen_mode,
1567 if tag_only: # pragma: no cover
1570 _decode_path, obj, tail = result
1571 if not _decode_path is decode_path:
1573 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1575 "explicit tag out-of-bound, longer than data",
1576 klass=self.__class__,
1577 decode_path=decode_path,
1580 yield decode_path, obj, (tail if leavemm else tail.tobytes())
1582 def decod(self, data, offset=0, decode_path=(), ctx=None):
1583 """Decode the data, check that tail is empty
1585 :raises ExceedingData: if tail is not empty
1587 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1588 (decode without tail) that also checks that there is no
1591 obj, tail = self.decode(
1594 decode_path=decode_path,
1599 raise ExceedingData(len(tail))
1602 def hexdecode(self, data, *args, **kwargs):
1603 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1605 return self.decode(hexdec(data), *args, **kwargs)
1607 def hexdecod(self, data, *args, **kwargs):
1608 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1610 return self.decod(hexdec(data), *args, **kwargs)
1614 """See :ref:`decoding`
1616 return self._expl is not None
1620 """See :ref:`decoding`
1625 def expl_tlen(self):
1626 """See :ref:`decoding`
1628 return len(self._expl)
1631 def expl_llen(self):
1632 """See :ref:`decoding`
1634 if self.expl_lenindef:
1636 return len(len_encode(self.tlvlen))
1639 def expl_offset(self):
1640 """See :ref:`decoding`
1642 return self.offset - self.expl_tlen - self.expl_llen
1645 def expl_vlen(self):
1646 """See :ref:`decoding`
1651 def expl_tlvlen(self):
1652 """See :ref:`decoding`
1654 return self.expl_tlen + self.expl_llen + self.expl_vlen
1657 def fulloffset(self):
1658 """See :ref:`decoding`
1660 return self.expl_offset if self.expled else self.offset
1664 """See :ref:`decoding`
1666 return self.expl_tlvlen if self.expled else self.tlvlen
1668 def pps_lenindef(self, decode_path):
1669 if self.lenindef and not (
1670 getattr(self, "defined", None) is not None and
1671 self.defined[1].lenindef
1674 asn1_type_name="EOC",
1676 decode_path=decode_path,
1678 self.offset + self.tlvlen -
1679 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1687 if self.expl_lenindef:
1689 asn1_type_name="EOC",
1690 obj_name="EXPLICIT",
1691 decode_path=decode_path,
1692 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1701 def encode_cer(obj):
1702 """Encode to CER in memory
1705 obj.encode_cer(buf.write)
1706 return buf.getvalue()
1709 class DecodePathDefBy(object):
1710 """DEFINED BY representation inside decode path
1712 __slots__ = ("defined_by",)
1714 def __init__(self, defined_by):
1715 self.defined_by = defined_by
1717 def __ne__(self, their):
1718 return not(self == their)
1720 def __eq__(self, their):
1721 if not isinstance(their, self.__class__):
1723 return self.defined_by == their.defined_by
1726 return "DEFINED BY " + str(self.defined_by)
1729 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1732 ########################################################################
1734 ########################################################################
1736 PP = namedtuple("PP", (
1759 ), **NAMEDTUPLE_KWARGS)
1764 asn1_type_name="unknown",
1781 expl_lenindef=False,
1812 def _colourize(what, colour, with_colours, attrs=("bold",)):
1813 return colored(what, colour, attrs=attrs) if with_colours else what
1816 def colonize_hex(hexed):
1817 """Separate hexadecimal string with colons
1819 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1828 with_decode_path=False,
1829 decode_path_len_decrease=0,
1836 " " if pp.expl_offset is None else
1837 ("-%d" % (pp.offset - pp.expl_offset))
1839 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1841 col = _colourize(col, "red", with_colours, ())
1842 col += _colourize("B", "red", with_colours) if pp.bered else " "
1844 col = "[%d,%d,%4d]%s" % (
1848 LENINDEF_PP_CHAR if pp.lenindef else " "
1850 col = _colourize(col, "green", with_colours, ())
1852 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1853 if decode_path_len > 0:
1854 cols.append(" ." * decode_path_len)
1855 ent = pp.decode_path[-1]
1856 if isinstance(ent, DecodePathDefBy):
1857 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1858 value = str(ent.defined_by)
1861 len(oid_maps) > 0 and
1862 ent.defined_by.asn1_type_name ==
1863 ObjectIdentifier.asn1_type_name
1865 for oid_map in oid_maps:
1866 oid_name = oid_map.get(value)
1867 if oid_name is not None:
1868 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1870 if oid_name is None:
1871 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1873 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1874 if pp.expl is not None:
1875 klass, _, num = pp.expl
1876 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1877 cols.append(_colourize(col, "blue", with_colours))
1878 if pp.impl is not None:
1879 klass, _, num = pp.impl
1880 col = "[%s%d]" % (TagClassReprs[klass], num)
1881 cols.append(_colourize(col, "blue", with_colours))
1882 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1883 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1885 cols.append(_colourize("BER", "red", with_colours))
1886 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1887 if pp.value is not None:
1889 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1891 len(oid_maps) > 0 and
1892 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1894 for oid_map in oid_maps:
1895 oid_name = oid_map.get(value)
1896 if oid_name is not None:
1897 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1899 if pp.asn1_type_name == Integer.asn1_type_name:
1900 hex_repr = hex(int(pp.obj._value))[2:].upper()
1901 if len(hex_repr) % 2 != 0:
1902 hex_repr = "0" + hex_repr
1903 cols.append(_colourize(
1904 "(%s)" % colonize_hex(hex_repr),
1909 if pp.blob.__class__ == binary_type:
1910 cols.append(hexenc(pp.blob))
1911 elif pp.blob.__class__ == tuple:
1912 cols.append(", ".join(pp.blob))
1914 cols.append(_colourize("OPTIONAL", "red", with_colours))
1916 cols.append(_colourize("DEFAULT", "red", with_colours))
1917 if with_decode_path:
1918 cols.append(_colourize(
1919 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1923 return " ".join(cols)
1926 def pp_console_blob(pp, decode_path_len_decrease=0):
1927 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1928 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1929 if decode_path_len > 0:
1930 cols.append(" ." * (decode_path_len + 1))
1931 if pp.blob.__class__ == binary_type:
1932 blob = hexenc(pp.blob).upper()
1933 for i in six_xrange(0, len(blob), 32):
1934 chunk = blob[i:i + 32]
1935 yield " ".join(cols + [colonize_hex(chunk)])
1936 elif pp.blob.__class__ == tuple:
1937 yield " ".join(cols + [", ".join(pp.blob)])
1945 with_decode_path=False,
1946 decode_path_only=(),
1949 """Pretty print object
1951 :param Obj obj: object you want to pretty print
1952 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1953 Its human readable form is printed when OID is met
1954 :param big_blobs: if large binary objects are met (like OctetString
1955 values), do we need to print them too, on separate
1957 :param with_colours: colourize output, if ``termcolor`` library
1959 :param with_decode_path: print decode path
1960 :param decode_path_only: print only that specified decode path
1962 def _pprint_pps(pps):
1964 if hasattr(pp, "_fields"):
1966 decode_path_only != () and
1968 str(p) for p in pp.decode_path[:len(decode_path_only)]
1969 ) != decode_path_only
1973 yield pp_console_row(
1978 with_colours=with_colours,
1979 with_decode_path=with_decode_path,
1980 decode_path_len_decrease=len(decode_path_only),
1982 for row in pp_console_blob(
1984 decode_path_len_decrease=len(decode_path_only),
1988 yield pp_console_row(
1993 with_colours=with_colours,
1994 with_decode_path=with_decode_path,
1995 decode_path_len_decrease=len(decode_path_only),
1998 for row in _pprint_pps(pp):
2000 return "\n".join(_pprint_pps(obj.pps(decode_path)))
2003 ########################################################################
2004 # ASN.1 primitive types
2005 ########################################################################
2007 BooleanState = namedtuple(
2009 BasicState._fields + ("value",),
2015 """``BOOLEAN`` boolean type
2017 >>> b = Boolean(True)
2019 >>> b == Boolean(True)
2025 tag_default = tag_encode(1)
2026 asn1_type_name = "BOOLEAN"
2038 :param value: set the value. Either boolean type, or
2039 :py:class:`pyderasn.Boolean` object
2040 :param bytes impl: override default tag with ``IMPLICIT`` one
2041 :param bytes expl: override default tag with ``EXPLICIT`` one
2042 :param default: set default value. Type same as in ``value``
2043 :param bool optional: is object ``OPTIONAL`` in sequence
2045 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
2046 self._value = None if value is None else self._value_sanitize(value)
2047 if default is not None:
2048 default = self._value_sanitize(default)
2049 self.default = self.__class__(
2055 self._value = default
2057 def _value_sanitize(self, value):
2058 if value.__class__ == bool:
2060 if issubclass(value.__class__, Boolean):
2062 raise InvalidValueType((self.__class__, bool))
2066 return self._value is not None
2068 def __getstate__(self):
2069 return BooleanState(
2085 def __setstate__(self, state):
2086 super(Boolean, self).__setstate__(state)
2087 self._value = state.value
2089 def __nonzero__(self):
2090 self._assert_ready()
2094 self._assert_ready()
2097 def __eq__(self, their):
2098 if their.__class__ == bool:
2099 return self._value == their
2100 if not issubclass(their.__class__, Boolean):
2103 self._value == their._value and
2104 self.tag == their.tag and
2105 self._expl == their._expl
2116 return self.__class__(
2118 impl=self.tag if impl is None else impl,
2119 expl=self._expl if expl is None else expl,
2120 default=self.default if default is None else default,
2121 optional=self.optional if optional is None else optional,
2125 self._assert_ready()
2129 (b"\xFF" if self._value else b"\x00"),
2132 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2134 t, _, lv = tag_strip(tlv)
2135 except DecodeError as err:
2136 raise err.__class__(
2138 klass=self.__class__,
2139 decode_path=decode_path,
2144 klass=self.__class__,
2145 decode_path=decode_path,
2152 l, _, v = len_decode(lv)
2153 except DecodeError as err:
2154 raise err.__class__(
2156 klass=self.__class__,
2157 decode_path=decode_path,
2161 raise InvalidLength(
2162 "Boolean's length must be equal to 1",
2163 klass=self.__class__,
2164 decode_path=decode_path,
2168 raise NotEnoughData(
2169 "encoded length is longer than data",
2170 klass=self.__class__,
2171 decode_path=decode_path,
2174 first_octet = byte2int(v)
2176 if first_octet == 0:
2178 elif first_octet == 0xFF:
2180 elif ctx.get("bered", False):
2185 "unacceptable Boolean value",
2186 klass=self.__class__,
2187 decode_path=decode_path,
2190 obj = self.__class__(
2194 default=self.default,
2195 optional=self.optional,
2196 _decoded=(offset, 1, 1),
2198 obj.ber_encoded = ber_encoded
2199 yield decode_path, obj, v[1:]
2202 return pp_console_row(next(self.pps()))
2204 def pps(self, decode_path=()):
2207 asn1_type_name=self.asn1_type_name,
2208 obj_name=self.__class__.__name__,
2209 decode_path=decode_path,
2210 value=str(self._value) if self.ready else None,
2211 optional=self.optional,
2212 default=self == self.default,
2213 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2214 expl=None if self._expl is None else tag_decode(self._expl),
2219 expl_offset=self.expl_offset if self.expled else None,
2220 expl_tlen=self.expl_tlen if self.expled else None,
2221 expl_llen=self.expl_llen if self.expled else None,
2222 expl_vlen=self.expl_vlen if self.expled else None,
2223 expl_lenindef=self.expl_lenindef,
2224 ber_encoded=self.ber_encoded,
2227 for pp in self.pps_lenindef(decode_path):
2231 IntegerState = namedtuple(
2233 BasicState._fields + ("specs", "value", "bound_min", "bound_max"),
2239 """``INTEGER`` integer type
2241 >>> b = Integer(-123)
2243 >>> b == Integer(-123)
2248 >>> Integer(2, bounds=(1, 3))
2250 >>> Integer(5, bounds=(1, 3))
2251 Traceback (most recent call last):
2252 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2256 class Version(Integer):
2263 >>> v = Version("v1")
2270 {'v3': 2, 'v1': 0, 'v2': 1}
2272 __slots__ = ("specs", "_bound_min", "_bound_max")
2273 tag_default = tag_encode(2)
2274 asn1_type_name = "INTEGER"
2288 :param value: set the value. Either integer type, named value
2289 (if ``schema`` is specified in the class), or
2290 :py:class:`pyderasn.Integer` object
2291 :param bounds: set ``(MIN, MAX)`` value constraint.
2292 (-inf, +inf) by default
2293 :param bytes impl: override default tag with ``IMPLICIT`` one
2294 :param bytes expl: override default tag with ``EXPLICIT`` one
2295 :param default: set default value. Type same as in ``value``
2296 :param bool optional: is object ``OPTIONAL`` in sequence
2298 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2300 specs = getattr(self, "schema", {}) if _specs is None else _specs
2301 self.specs = specs if specs.__class__ == dict else dict(specs)
2302 self._bound_min, self._bound_max = getattr(
2305 (float("-inf"), float("+inf")),
2306 ) if bounds is None else bounds
2307 if value is not None:
2308 self._value = self._value_sanitize(value)
2309 if default is not None:
2310 default = self._value_sanitize(default)
2311 self.default = self.__class__(
2317 if self._value is None:
2318 self._value = default
2320 def _value_sanitize(self, value):
2321 if isinstance(value, integer_types):
2323 elif issubclass(value.__class__, Integer):
2324 value = value._value
2325 elif value.__class__ == str:
2326 value = self.specs.get(value)
2328 raise ObjUnknown("integer value: %s" % value)
2330 raise InvalidValueType((self.__class__, int, str))
2331 if not self._bound_min <= value <= self._bound_max:
2332 raise BoundsError(self._bound_min, value, self._bound_max)
2337 return self._value is not None
2339 def __getstate__(self):
2340 return IntegerState(
2359 def __setstate__(self, state):
2360 super(Integer, self).__setstate__(state)
2361 self.specs = state.specs
2362 self._value = state.value
2363 self._bound_min = state.bound_min
2364 self._bound_max = state.bound_max
2367 self._assert_ready()
2368 return int(self._value)
2371 self._assert_ready()
2374 bytes(self._expl or b"") +
2375 str(self._value).encode("ascii"),
2378 def __eq__(self, their):
2379 if isinstance(their, integer_types):
2380 return self._value == their
2381 if not issubclass(their.__class__, Integer):
2384 self._value == their._value and
2385 self.tag == their.tag and
2386 self._expl == their._expl
2389 def __lt__(self, their):
2390 return self._value < their._value
2394 """Return named representation (if exists) of the value
2396 for name, value in iteritems(self.specs):
2397 if value == self._value:
2410 return self.__class__(
2413 (self._bound_min, self._bound_max)
2414 if bounds is None else bounds
2416 impl=self.tag if impl is None else impl,
2417 expl=self._expl if expl is None else expl,
2418 default=self.default if default is None else default,
2419 optional=self.optional if optional is None else optional,
2424 self._assert_ready()
2428 octets = bytearray([0])
2432 octets = bytearray()
2434 octets.append((value & 0xFF) ^ 0xFF)
2436 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2439 octets = bytearray()
2441 octets.append(value & 0xFF)
2443 if octets[-1] & 0x80 > 0:
2446 octets = bytes(octets)
2448 bytes_len = ceil(value.bit_length() / 8) or 1
2451 octets = value.to_bytes(
2456 except OverflowError:
2460 return b"".join((self.tag, len_encode(len(octets)), octets))
2462 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2464 t, _, lv = tag_strip(tlv)
2465 except DecodeError as err:
2466 raise err.__class__(
2468 klass=self.__class__,
2469 decode_path=decode_path,
2474 klass=self.__class__,
2475 decode_path=decode_path,
2482 l, llen, v = len_decode(lv)
2483 except DecodeError as err:
2484 raise err.__class__(
2486 klass=self.__class__,
2487 decode_path=decode_path,
2491 raise NotEnoughData(
2492 "encoded length is longer than data",
2493 klass=self.__class__,
2494 decode_path=decode_path,
2498 raise NotEnoughData(
2500 klass=self.__class__,
2501 decode_path=decode_path,
2504 v, tail = v[:l], v[l:]
2505 first_octet = byte2int(v)
2507 second_octet = byte2int(v[1:])
2509 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2510 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2513 "non normalized integer",
2514 klass=self.__class__,
2515 decode_path=decode_path,
2520 if first_octet & 0x80 > 0:
2521 octets = bytearray()
2522 for octet in bytearray(v):
2523 octets.append(octet ^ 0xFF)
2524 for octet in octets:
2525 value = (value << 8) | octet
2529 for octet in bytearray(v):
2530 value = (value << 8) | octet
2532 value = int.from_bytes(v, byteorder="big", signed=True)
2534 obj = self.__class__(
2536 bounds=(self._bound_min, self._bound_max),
2539 default=self.default,
2540 optional=self.optional,
2542 _decoded=(offset, llen, l),
2544 except BoundsError as err:
2547 klass=self.__class__,
2548 decode_path=decode_path,
2551 yield decode_path, obj, tail
2554 return pp_console_row(next(self.pps()))
2556 def pps(self, decode_path=()):
2559 asn1_type_name=self.asn1_type_name,
2560 obj_name=self.__class__.__name__,
2561 decode_path=decode_path,
2562 value=(self.named or str(self._value)) if self.ready else None,
2563 optional=self.optional,
2564 default=self == self.default,
2565 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2566 expl=None if self._expl is None else tag_decode(self._expl),
2571 expl_offset=self.expl_offset if self.expled else None,
2572 expl_tlen=self.expl_tlen if self.expled else None,
2573 expl_llen=self.expl_llen if self.expled else None,
2574 expl_vlen=self.expl_vlen if self.expled else None,
2575 expl_lenindef=self.expl_lenindef,
2578 for pp in self.pps_lenindef(decode_path):
2582 BitStringState = namedtuple(
2584 BasicState._fields + ("specs", "value", "tag_constructed", "defined"),
2589 class BitString(Obj):
2590 """``BIT STRING`` bit string type
2592 >>> BitString(b"hello world")
2593 BIT STRING 88 bits 68656c6c6f20776f726c64
2596 >>> b == b"hello world"
2601 >>> BitString("'0A3B5F291CD'H")
2602 BIT STRING 44 bits 0a3b5f291cd0
2603 >>> b = BitString("'010110000000'B")
2604 BIT STRING 12 bits 5800
2607 >>> b[0], b[1], b[2], b[3]
2608 (False, True, False, True)
2612 [False, True, False, True, True, False, False, False, False, False, False, False]
2616 class KeyUsage(BitString):
2618 ("digitalSignature", 0),
2619 ("nonRepudiation", 1),
2620 ("keyEncipherment", 2),
2623 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2624 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2626 ['nonRepudiation', 'keyEncipherment']
2628 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2632 Pay attention that BIT STRING can be encoded both in primitive
2633 and constructed forms. Decoder always checks constructed form tag
2634 additionally to specified primitive one. If BER decoding is
2635 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2636 of DER restrictions.
2638 __slots__ = ("tag_constructed", "specs", "defined")
2639 tag_default = tag_encode(3)
2640 asn1_type_name = "BIT STRING"
2653 :param value: set the value. Either binary type, tuple of named
2654 values (if ``schema`` is specified in the class),
2655 string in ``'XXX...'B`` form, or
2656 :py:class:`pyderasn.BitString` object
2657 :param bytes impl: override default tag with ``IMPLICIT`` one
2658 :param bytes expl: override default tag with ``EXPLICIT`` one
2659 :param default: set default value. Type same as in ``value``
2660 :param bool optional: is object ``OPTIONAL`` in sequence
2662 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2663 specs = getattr(self, "schema", {}) if _specs is None else _specs
2664 self.specs = specs if specs.__class__ == dict else dict(specs)
2665 self._value = None if value is None else self._value_sanitize(value)
2666 if default is not None:
2667 default = self._value_sanitize(default)
2668 self.default = self.__class__(
2674 self._value = default
2676 tag_klass, _, tag_num = tag_decode(self.tag)
2677 self.tag_constructed = tag_encode(
2679 form=TagFormConstructed,
2683 def _bits2octets(self, bits):
2684 if len(self.specs) > 0:
2685 bits = bits.rstrip("0")
2687 bits += "0" * ((8 - (bit_len % 8)) % 8)
2688 octets = bytearray(len(bits) // 8)
2689 for i in six_xrange(len(octets)):
2690 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2691 return bit_len, bytes(octets)
2693 def _value_sanitize(self, value):
2694 if isinstance(value, (string_types, binary_type)):
2696 isinstance(value, string_types) and
2697 value.startswith("'")
2699 if value.endswith("'B"):
2701 if not frozenset(value) <= SET01:
2702 raise ValueError("B's coding contains unacceptable chars")
2703 return self._bits2octets(value)
2704 if value.endswith("'H"):
2708 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2710 if value.__class__ == binary_type:
2711 return (len(value) * 8, value)
2712 raise InvalidValueType((self.__class__, string_types, binary_type))
2713 if value.__class__ == tuple:
2716 isinstance(value[0], integer_types) and
2717 value[1].__class__ == binary_type
2722 bit = self.specs.get(name)
2724 raise ObjUnknown("BitString value: %s" % name)
2727 return self._bits2octets("")
2728 bits = frozenset(bits)
2729 return self._bits2octets("".join(
2730 ("1" if bit in bits else "0")
2731 for bit in six_xrange(max(bits) + 1)
2733 if issubclass(value.__class__, BitString):
2735 raise InvalidValueType((self.__class__, binary_type, string_types))
2739 return self._value is not None
2741 def __getstate__(self):
2742 return BitStringState(
2757 self.tag_constructed,
2761 def __setstate__(self, state):
2762 super(BitString, self).__setstate__(state)
2763 self.specs = state.specs
2764 self._value = state.value
2765 self.tag_constructed = state.tag_constructed
2766 self.defined = state.defined
2769 self._assert_ready()
2770 for i in six_xrange(self._value[0]):
2775 """Returns number of bits in the string
2777 self._assert_ready()
2778 return self._value[0]
2780 def __bytes__(self):
2781 self._assert_ready()
2782 return self._value[1]
2784 def __eq__(self, their):
2785 if their.__class__ == bytes:
2786 return self._value[1] == their
2787 if not issubclass(their.__class__, BitString):
2790 self._value == their._value and
2791 self.tag == their.tag and
2792 self._expl == their._expl
2797 """Named representation (if exists) of the bits
2799 :returns: [str(name), ...]
2801 return [name for name, bit in iteritems(self.specs) if self[bit]]
2811 return self.__class__(
2813 impl=self.tag if impl is None else impl,
2814 expl=self._expl if expl is None else expl,
2815 default=self.default if default is None else default,
2816 optional=self.optional if optional is None else optional,
2820 def __getitem__(self, key):
2821 if key.__class__ == int:
2822 bit_len, octets = self._value
2826 byte2int(memoryview(octets)[key // 8:]) >>
2829 if isinstance(key, string_types):
2830 value = self.specs.get(key)
2832 raise ObjUnknown("BitString value: %s" % key)
2834 raise InvalidValueType((int, str))
2837 self._assert_ready()
2838 bit_len, octets = self._value
2841 len_encode(len(octets) + 1),
2842 int2byte((8 - bit_len % 8) % 8),
2846 def _encode_cer(self, writer):
2847 bit_len, octets = self._value
2848 if len(octets) + 1 <= 1000:
2849 write_full(writer, self._encode())
2851 write_full(writer, self.tag_constructed)
2852 write_full(writer, LENINDEF)
2853 for offset in six_xrange(0, (len(octets) // 999) * 999, 999):
2854 write_full(writer, b"".join((
2855 BitString.tag_default,
2858 octets[offset:offset + 999],
2860 tail = octets[offset+999:]
2862 tail = int2byte((8 - bit_len % 8) % 8) + tail
2863 write_full(writer, b"".join((
2864 BitString.tag_default,
2865 len_encode(len(tail)),
2868 write_full(writer, EOC)
2870 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2872 t, tlen, lv = tag_strip(tlv)
2873 except DecodeError as err:
2874 raise err.__class__(
2876 klass=self.__class__,
2877 decode_path=decode_path,
2881 if tag_only: # pragma: no cover
2885 l, llen, v = len_decode(lv)
2886 except DecodeError as err:
2887 raise err.__class__(
2889 klass=self.__class__,
2890 decode_path=decode_path,
2894 raise NotEnoughData(
2895 "encoded length is longer than data",
2896 klass=self.__class__,
2897 decode_path=decode_path,
2901 raise NotEnoughData(
2903 klass=self.__class__,
2904 decode_path=decode_path,
2907 pad_size = byte2int(v)
2908 if l == 1 and pad_size != 0:
2910 "invalid empty value",
2911 klass=self.__class__,
2912 decode_path=decode_path,
2918 klass=self.__class__,
2919 decode_path=decode_path,
2922 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2925 klass=self.__class__,
2926 decode_path=decode_path,
2929 v, tail = v[:l], v[l:]
2930 bit_len = (len(v) - 1) * 8 - pad_size
2931 obj = self.__class__(
2932 value=None if evgen_mode else (bit_len, v[1:].tobytes()),
2935 default=self.default,
2936 optional=self.optional,
2938 _decoded=(offset, llen, l),
2941 obj._value = (bit_len, None)
2942 yield decode_path, obj, tail
2944 if t != self.tag_constructed:
2946 klass=self.__class__,
2947 decode_path=decode_path,
2950 if not ctx.get("bered", False):
2952 "unallowed BER constructed encoding",
2953 klass=self.__class__,
2954 decode_path=decode_path,
2957 if tag_only: # pragma: no cover
2962 l, llen, v = len_decode(lv)
2963 except LenIndefForm:
2964 llen, l, v = 1, 0, lv[1:]
2966 except DecodeError as err:
2967 raise err.__class__(
2969 klass=self.__class__,
2970 decode_path=decode_path,
2974 raise NotEnoughData(
2975 "encoded length is longer than data",
2976 klass=self.__class__,
2977 decode_path=decode_path,
2980 if not lenindef and l == 0:
2981 raise NotEnoughData(
2983 klass=self.__class__,
2984 decode_path=decode_path,
2988 sub_offset = offset + tlen + llen
2992 if v[:EOC_LEN].tobytes() == EOC:
2999 "chunk out of bounds",
3000 klass=self.__class__,
3001 decode_path=decode_path + (str(len(chunks) - 1),),
3002 offset=chunks[-1].offset,
3004 sub_decode_path = decode_path + (str(len(chunks)),)
3007 for _decode_path, chunk, v_tail in BitString().decode_evgen(
3010 decode_path=sub_decode_path,
3013 _ctx_immutable=False,
3015 yield _decode_path, chunk, v_tail
3017 _, chunk, v_tail = next(BitString().decode_evgen(
3020 decode_path=sub_decode_path,
3023 _ctx_immutable=False,
3028 "expected BitString encoded chunk",
3029 klass=self.__class__,
3030 decode_path=sub_decode_path,
3033 chunks.append(chunk)
3034 sub_offset += chunk.tlvlen
3035 vlen += chunk.tlvlen
3037 if len(chunks) == 0:
3040 klass=self.__class__,
3041 decode_path=decode_path,
3046 for chunk_i, chunk in enumerate(chunks[:-1]):
3047 if chunk.bit_len % 8 != 0:
3049 "BitString chunk is not multiple of 8 bits",
3050 klass=self.__class__,
3051 decode_path=decode_path + (str(chunk_i),),
3052 offset=chunk.offset,
3055 values.append(bytes(chunk))
3056 bit_len += chunk.bit_len
3057 chunk_last = chunks[-1]
3059 values.append(bytes(chunk_last))
3060 bit_len += chunk_last.bit_len
3061 obj = self.__class__(
3062 value=None if evgen_mode else (bit_len, b"".join(values)),
3065 default=self.default,
3066 optional=self.optional,
3068 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3071 obj._value = (bit_len, None)
3072 obj.lenindef = lenindef
3073 obj.ber_encoded = True
3074 yield decode_path, obj, (v[EOC_LEN:] if lenindef else v)
3077 return pp_console_row(next(self.pps()))
3079 def pps(self, decode_path=()):
3083 bit_len, blob = self._value
3084 value = "%d bits" % bit_len
3085 if len(self.specs) > 0 and blob is not None:
3086 blob = tuple(self.named)
3089 asn1_type_name=self.asn1_type_name,
3090 obj_name=self.__class__.__name__,
3091 decode_path=decode_path,
3094 optional=self.optional,
3095 default=self == self.default,
3096 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3097 expl=None if self._expl is None else tag_decode(self._expl),
3102 expl_offset=self.expl_offset if self.expled else None,
3103 expl_tlen=self.expl_tlen if self.expled else None,
3104 expl_llen=self.expl_llen if self.expled else None,
3105 expl_vlen=self.expl_vlen if self.expled else None,
3106 expl_lenindef=self.expl_lenindef,
3107 lenindef=self.lenindef,
3108 ber_encoded=self.ber_encoded,
3111 defined_by, defined = self.defined or (None, None)
3112 if defined_by is not None:
3114 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3116 for pp in self.pps_lenindef(decode_path):
3120 OctetStringState = namedtuple(
3122 BasicState._fields + (
3133 class OctetString(Obj):
3134 """``OCTET STRING`` binary string type
3136 >>> s = OctetString(b"hello world")
3137 OCTET STRING 11 bytes 68656c6c6f20776f726c64
3138 >>> s == OctetString(b"hello world")
3143 >>> OctetString(b"hello", bounds=(4, 4))
3144 Traceback (most recent call last):
3145 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
3146 >>> OctetString(b"hell", bounds=(4, 4))
3147 OCTET STRING 4 bytes 68656c6c
3151 Pay attention that OCTET STRING can be encoded both in primitive
3152 and constructed forms. Decoder always checks constructed form tag
3153 additionally to specified primitive one. If BER decoding is
3154 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
3155 of DER restrictions.
3157 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
3158 tag_default = tag_encode(4)
3159 asn1_type_name = "OCTET STRING"
3160 evgen_mode_skip_value = True
3174 :param value: set the value. Either binary type, or
3175 :py:class:`pyderasn.OctetString` object
3176 :param bounds: set ``(MIN, MAX)`` value size constraint.
3177 (-inf, +inf) by default
3178 :param bytes impl: override default tag with ``IMPLICIT`` one
3179 :param bytes expl: override default tag with ``EXPLICIT`` one
3180 :param default: set default value. Type same as in ``value``
3181 :param bool optional: is object ``OPTIONAL`` in sequence
3183 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
3185 self._bound_min, self._bound_max = getattr(
3189 ) if bounds is None else bounds
3190 if value is not None:
3191 self._value = self._value_sanitize(value)
3192 if default is not None:
3193 default = self._value_sanitize(default)
3194 self.default = self.__class__(
3199 if self._value is None:
3200 self._value = default
3202 tag_klass, _, tag_num = tag_decode(self.tag)
3203 self.tag_constructed = tag_encode(
3205 form=TagFormConstructed,
3209 def _value_sanitize(self, value):
3210 if value.__class__ == binary_type:
3212 elif issubclass(value.__class__, OctetString):
3213 value = value._value
3215 raise InvalidValueType((self.__class__, bytes))
3216 if not self._bound_min <= len(value) <= self._bound_max:
3217 raise BoundsError(self._bound_min, len(value), self._bound_max)
3222 return self._value is not None
3224 def __getstate__(self):
3225 return OctetStringState(
3241 self.tag_constructed,
3245 def __setstate__(self, state):
3246 super(OctetString, self).__setstate__(state)
3247 self._value = state.value
3248 self._bound_min = state.bound_min
3249 self._bound_max = state.bound_max
3250 self.tag_constructed = state.tag_constructed
3251 self.defined = state.defined
3253 def __bytes__(self):
3254 self._assert_ready()
3257 def __eq__(self, their):
3258 if their.__class__ == binary_type:
3259 return self._value == their
3260 if not issubclass(their.__class__, OctetString):
3263 self._value == their._value and
3264 self.tag == their.tag and
3265 self._expl == their._expl
3268 def __lt__(self, their):
3269 return self._value < their._value
3280 return self.__class__(
3283 (self._bound_min, self._bound_max)
3284 if bounds is None else bounds
3286 impl=self.tag if impl is None else impl,
3287 expl=self._expl if expl is None else expl,
3288 default=self.default if default is None else default,
3289 optional=self.optional if optional is None else optional,
3293 self._assert_ready()
3296 len_encode(len(self._value)),
3300 def _encode_cer(self, writer):
3301 octets = self._value
3302 if len(octets) <= 1000:
3303 write_full(writer, self._encode())
3305 write_full(writer, self.tag_constructed)
3306 write_full(writer, LENINDEF)
3307 for offset in six_xrange(0, (len(octets) // 1000) * 1000, 1000):
3308 write_full(writer, b"".join((
3309 OctetString.tag_default,
3311 octets[offset:offset + 1000],
3313 tail = octets[offset+1000:]
3315 write_full(writer, b"".join((
3316 OctetString.tag_default,
3317 len_encode(len(tail)),
3320 write_full(writer, EOC)
3322 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3324 t, tlen, lv = tag_strip(tlv)
3325 except DecodeError as err:
3326 raise err.__class__(
3328 klass=self.__class__,
3329 decode_path=decode_path,
3337 l, llen, v = len_decode(lv)
3338 except DecodeError as err:
3339 raise err.__class__(
3341 klass=self.__class__,
3342 decode_path=decode_path,
3346 raise NotEnoughData(
3347 "encoded length is longer than data",
3348 klass=self.__class__,
3349 decode_path=decode_path,
3352 v, tail = v[:l], v[l:]
3353 if evgen_mode and not self._bound_min <= len(v) <= self._bound_max:
3355 msg=str(BoundsError(self._bound_min, len(v), self._bound_max)),
3356 klass=self.__class__,
3357 decode_path=decode_path,
3361 obj = self.__class__(
3363 None if (evgen_mode and self.evgen_mode_skip_value)
3366 bounds=(self._bound_min, self._bound_max),
3369 default=self.default,
3370 optional=self.optional,
3371 _decoded=(offset, llen, l),
3374 except DecodeError as err:
3377 klass=self.__class__,
3378 decode_path=decode_path,
3381 except BoundsError as err:
3384 klass=self.__class__,
3385 decode_path=decode_path,
3388 yield decode_path, obj, tail
3390 if t != self.tag_constructed:
3392 klass=self.__class__,
3393 decode_path=decode_path,
3396 if not ctx.get("bered", False):
3398 "unallowed BER constructed encoding",
3399 klass=self.__class__,
3400 decode_path=decode_path,
3408 l, llen, v = len_decode(lv)
3409 except LenIndefForm:
3410 llen, l, v = 1, 0, lv[1:]
3412 except DecodeError as err:
3413 raise err.__class__(
3415 klass=self.__class__,
3416 decode_path=decode_path,
3420 raise NotEnoughData(
3421 "encoded length is longer than data",
3422 klass=self.__class__,
3423 decode_path=decode_path,
3428 sub_offset = offset + tlen + llen
3433 if v[:EOC_LEN].tobytes() == EOC:
3440 "chunk out of bounds",
3441 klass=self.__class__,
3442 decode_path=decode_path + (str(len(chunks) - 1),),
3443 offset=chunks[-1].offset,
3447 sub_decode_path = decode_path + (str(chunks_count),)
3448 for _decode_path, chunk, v_tail in OctetString().decode_evgen(
3451 decode_path=sub_decode_path,
3454 _ctx_immutable=False,
3456 yield _decode_path, chunk, v_tail
3457 if not chunk.ber_encoded:
3458 payload_len += chunk.vlen
3461 sub_decode_path = decode_path + (str(len(chunks)),)
3462 _, chunk, v_tail = next(OctetString().decode_evgen(
3465 decode_path=sub_decode_path,
3468 _ctx_immutable=False,
3471 chunks.append(chunk)
3474 "expected OctetString encoded chunk",
3475 klass=self.__class__,
3476 decode_path=sub_decode_path,
3479 sub_offset += chunk.tlvlen
3480 vlen += chunk.tlvlen
3482 if evgen_mode and not self._bound_min <= payload_len <= self._bound_max:
3484 msg=str(BoundsError(self._bound_min, payload_len, self._bound_max)),
3485 klass=self.__class__,
3486 decode_path=decode_path,
3490 obj = self.__class__(
3492 None if evgen_mode else
3493 b"".join(bytes(chunk) for chunk in chunks)
3495 bounds=(self._bound_min, self._bound_max),
3498 default=self.default,
3499 optional=self.optional,
3500 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3503 except DecodeError as err:
3506 klass=self.__class__,
3507 decode_path=decode_path,
3510 except BoundsError as err:
3513 klass=self.__class__,
3514 decode_path=decode_path,
3517 obj.lenindef = lenindef
3518 obj.ber_encoded = True
3519 yield decode_path, obj, (v[EOC_LEN:] if lenindef else v)
3522 return pp_console_row(next(self.pps()))
3524 def pps(self, decode_path=()):
3527 asn1_type_name=self.asn1_type_name,
3528 obj_name=self.__class__.__name__,
3529 decode_path=decode_path,
3530 value=("%d bytes" % len(self._value)) if self.ready else None,
3531 blob=self._value if self.ready else None,
3532 optional=self.optional,
3533 default=self == self.default,
3534 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3535 expl=None if self._expl is None else tag_decode(self._expl),
3540 expl_offset=self.expl_offset if self.expled else None,
3541 expl_tlen=self.expl_tlen if self.expled else None,
3542 expl_llen=self.expl_llen if self.expled else None,
3543 expl_vlen=self.expl_vlen if self.expled else None,
3544 expl_lenindef=self.expl_lenindef,
3545 lenindef=self.lenindef,
3546 ber_encoded=self.ber_encoded,
3549 defined_by, defined = self.defined or (None, None)
3550 if defined_by is not None:
3552 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3554 for pp in self.pps_lenindef(decode_path):
3558 def agg_octet_string(evgens, decode_path, raw, writer):
3559 """Aggregate constructed string (OctetString and its derivatives)
3561 :param evgens: iterator of generated events
3562 :param decode_path: points to the string we want to decode
3563 :param raw: slicebable (memoryview, bytearray, etc) with
3564 the data evgens are generated one
3565 :param writer: buffer.write where string is going to be saved
3567 decode_path_len = len(decode_path)
3568 for dp, obj, _ in evgens:
3569 if dp[:decode_path_len] != decode_path:
3571 if not obj.ber_encoded:
3572 write_full(writer, raw[
3573 obj.offset + obj.tlen + obj.llen:
3574 obj.offset + obj.tlen + obj.llen + obj.vlen -
3575 (EOC_LEN if obj.expl_lenindef else 0)
3577 if len(dp) == decode_path_len:
3581 NullState = namedtuple("NullState", BasicState._fields, **NAMEDTUPLE_KWARGS)
3585 """``NULL`` null object
3593 tag_default = tag_encode(5)
3594 asn1_type_name = "NULL"
3598 value=None, # unused, but Sequence passes it
3605 :param bytes impl: override default tag with ``IMPLICIT`` one
3606 :param bytes expl: override default tag with ``EXPLICIT`` one
3607 :param bool optional: is object ``OPTIONAL`` in sequence
3609 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3616 def __getstate__(self):
3632 def __eq__(self, their):
3633 if not issubclass(their.__class__, Null):
3636 self.tag == their.tag and
3637 self._expl == their._expl
3647 return self.__class__(
3648 impl=self.tag if impl is None else impl,
3649 expl=self._expl if expl is None else expl,
3650 optional=self.optional if optional is None else optional,
3654 return self.tag + len_encode(0)
3656 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3658 t, _, lv = tag_strip(tlv)
3659 except DecodeError as err:
3660 raise err.__class__(
3662 klass=self.__class__,
3663 decode_path=decode_path,
3668 klass=self.__class__,
3669 decode_path=decode_path,
3672 if tag_only: # pragma: no cover
3676 l, _, v = len_decode(lv)
3677 except DecodeError as err:
3678 raise err.__class__(
3680 klass=self.__class__,
3681 decode_path=decode_path,
3685 raise InvalidLength(
3686 "Null must have zero length",
3687 klass=self.__class__,
3688 decode_path=decode_path,
3691 obj = self.__class__(
3694 optional=self.optional,
3695 _decoded=(offset, 1, 0),
3697 yield decode_path, obj, v
3700 return pp_console_row(next(self.pps()))
3702 def pps(self, decode_path=()):
3705 asn1_type_name=self.asn1_type_name,
3706 obj_name=self.__class__.__name__,
3707 decode_path=decode_path,
3708 optional=self.optional,
3709 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3710 expl=None if self._expl is None else tag_decode(self._expl),
3715 expl_offset=self.expl_offset if self.expled else None,
3716 expl_tlen=self.expl_tlen if self.expled else None,
3717 expl_llen=self.expl_llen if self.expled else None,
3718 expl_vlen=self.expl_vlen if self.expled else None,
3719 expl_lenindef=self.expl_lenindef,
3722 for pp in self.pps_lenindef(decode_path):
3726 ObjectIdentifierState = namedtuple(
3727 "ObjectIdentifierState",
3728 BasicState._fields + ("value", "defines"),
3733 class ObjectIdentifier(Obj):
3734 """``OBJECT IDENTIFIER`` OID type
3736 >>> oid = ObjectIdentifier((1, 2, 3))
3737 OBJECT IDENTIFIER 1.2.3
3738 >>> oid == ObjectIdentifier("1.2.3")
3744 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3745 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3747 >>> str(ObjectIdentifier((3, 1)))
3748 Traceback (most recent call last):
3749 pyderasn.InvalidOID: unacceptable first arc value
3751 __slots__ = ("defines",)
3752 tag_default = tag_encode(6)
3753 asn1_type_name = "OBJECT IDENTIFIER"
3766 :param value: set the value. Either tuples of integers,
3767 string of "."-concatenated integers, or
3768 :py:class:`pyderasn.ObjectIdentifier` object
3769 :param defines: sequence of tuples. Each tuple has two elements.
3770 First one is relative to current one decode
3771 path, aiming to the field defined by that OID.
3772 Read about relative path in
3773 :py:func:`pyderasn.abs_decode_path`. Second
3774 tuple element is ``{OID: pyderasn.Obj()}``
3775 dictionary, mapping between current OID value
3776 and structure applied to defined field.
3777 :ref:`Read about DEFINED BY <definedby>`
3778 :param bytes impl: override default tag with ``IMPLICIT`` one
3779 :param bytes expl: override default tag with ``EXPLICIT`` one
3780 :param default: set default value. Type same as in ``value``
3781 :param bool optional: is object ``OPTIONAL`` in sequence
3783 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3785 if value is not None:
3786 self._value = self._value_sanitize(value)
3787 if default is not None:
3788 default = self._value_sanitize(default)
3789 self.default = self.__class__(
3794 if self._value is None:
3795 self._value = default
3796 self.defines = defines
3798 def __add__(self, their):
3799 if their.__class__ == tuple:
3800 return self.__class__(self._value + their)
3801 if isinstance(their, self.__class__):
3802 return self.__class__(self._value + their._value)
3803 raise InvalidValueType((self.__class__, tuple))
3805 def _value_sanitize(self, value):
3806 if issubclass(value.__class__, ObjectIdentifier):
3808 if isinstance(value, string_types):
3810 value = tuple(pureint(arc) for arc in value.split("."))
3812 raise InvalidOID("unacceptable arcs values")
3813 if value.__class__ == tuple:
3815 raise InvalidOID("less than 2 arcs")
3816 first_arc = value[0]
3817 if first_arc in (0, 1):
3818 if not (0 <= value[1] <= 39):
3819 raise InvalidOID("second arc is too wide")
3820 elif first_arc == 2:
3823 raise InvalidOID("unacceptable first arc value")
3824 if not all(arc >= 0 for arc in value):
3825 raise InvalidOID("negative arc value")
3827 raise InvalidValueType((self.__class__, str, tuple))
3831 return self._value is not None
3833 def __getstate__(self):
3834 return ObjectIdentifierState(
3851 def __setstate__(self, state):
3852 super(ObjectIdentifier, self).__setstate__(state)
3853 self._value = state.value
3854 self.defines = state.defines
3857 self._assert_ready()
3858 return iter(self._value)
3861 return ".".join(str(arc) for arc in self._value or ())
3864 self._assert_ready()
3867 bytes(self._expl or b"") +
3868 str(self._value).encode("ascii"),
3871 def __eq__(self, their):
3872 if their.__class__ == tuple:
3873 return self._value == their
3874 if not issubclass(their.__class__, ObjectIdentifier):
3877 self.tag == their.tag and
3878 self._expl == their._expl and
3879 self._value == their._value
3882 def __lt__(self, their):
3883 return self._value < their._value
3894 return self.__class__(
3896 defines=self.defines if defines is None else defines,
3897 impl=self.tag if impl is None else impl,
3898 expl=self._expl if expl is None else expl,
3899 default=self.default if default is None else default,
3900 optional=self.optional if optional is None else optional,
3904 self._assert_ready()
3906 first_value = value[1]
3907 first_arc = value[0]
3910 elif first_arc == 1:
3912 elif first_arc == 2:
3914 else: # pragma: no cover
3915 raise RuntimeError("invalid arc is stored")
3916 octets = [zero_ended_encode(first_value)]
3917 for arc in value[2:]:
3918 octets.append(zero_ended_encode(arc))
3919 v = b"".join(octets)
3920 return b"".join((self.tag, len_encode(len(v)), v))
3922 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3924 t, _, lv = tag_strip(tlv)
3925 except DecodeError as err:
3926 raise err.__class__(
3928 klass=self.__class__,
3929 decode_path=decode_path,
3934 klass=self.__class__,
3935 decode_path=decode_path,
3938 if tag_only: # pragma: no cover
3942 l, llen, v = len_decode(lv)
3943 except DecodeError as err:
3944 raise err.__class__(
3946 klass=self.__class__,
3947 decode_path=decode_path,
3951 raise NotEnoughData(
3952 "encoded length is longer than data",
3953 klass=self.__class__,
3954 decode_path=decode_path,
3958 raise NotEnoughData(
3960 klass=self.__class__,
3961 decode_path=decode_path,
3964 v, tail = v[:l], v[l:]
3971 octet = indexbytes(v, i)
3972 if i == 0 and octet == 0x80:
3973 if ctx.get("bered", False):
3976 raise DecodeError("non normalized arc encoding")
3977 arc = (arc << 7) | (octet & 0x7F)
3978 if octet & 0x80 == 0:
3986 klass=self.__class__,
3987 decode_path=decode_path,
3991 second_arc = arcs[0]
3992 if 0 <= second_arc <= 39:
3994 elif 40 <= second_arc <= 79:
4000 obj = self.__class__(
4001 value=tuple([first_arc, second_arc] + arcs[1:]),
4004 default=self.default,
4005 optional=self.optional,
4006 _decoded=(offset, llen, l),
4009 obj.ber_encoded = True
4010 yield decode_path, obj, tail
4013 return pp_console_row(next(self.pps()))
4015 def pps(self, decode_path=()):
4018 asn1_type_name=self.asn1_type_name,
4019 obj_name=self.__class__.__name__,
4020 decode_path=decode_path,
4021 value=str(self) if self.ready else None,
4022 optional=self.optional,
4023 default=self == self.default,
4024 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4025 expl=None if self._expl is None else tag_decode(self._expl),
4030 expl_offset=self.expl_offset if self.expled else None,
4031 expl_tlen=self.expl_tlen if self.expled else None,
4032 expl_llen=self.expl_llen if self.expled else None,
4033 expl_vlen=self.expl_vlen if self.expled else None,
4034 expl_lenindef=self.expl_lenindef,
4035 ber_encoded=self.ber_encoded,
4038 for pp in self.pps_lenindef(decode_path):
4042 class Enumerated(Integer):
4043 """``ENUMERATED`` integer type
4045 This type is identical to :py:class:`pyderasn.Integer`, but requires
4046 schema to be specified and does not accept values missing from it.
4049 tag_default = tag_encode(10)
4050 asn1_type_name = "ENUMERATED"
4061 bounds=None, # dummy argument, workability for Integer.decode
4063 super(Enumerated, self).__init__(
4064 value, bounds, impl, expl, default, optional, _specs, _decoded,
4066 if len(self.specs) == 0:
4067 raise ValueError("schema must be specified")
4069 def _value_sanitize(self, value):
4070 if isinstance(value, self.__class__):
4071 value = value._value
4072 elif isinstance(value, integer_types):
4073 for _value in itervalues(self.specs):
4078 "unknown integer value: %s" % value,
4079 klass=self.__class__,
4081 elif isinstance(value, string_types):
4082 value = self.specs.get(value)
4084 raise ObjUnknown("integer value: %s" % value)
4086 raise InvalidValueType((self.__class__, int, str))
4098 return self.__class__(
4100 impl=self.tag if impl is None else impl,
4101 expl=self._expl if expl is None else expl,
4102 default=self.default if default is None else default,
4103 optional=self.optional if optional is None else optional,
4108 def escape_control_unicode(c):
4109 if unicat(c)[0] == "C":
4110 c = repr(c).lstrip("u").strip("'")
4114 class CommonString(OctetString):
4115 """Common class for all strings
4117 Everything resembles :py:class:`pyderasn.OctetString`, except
4118 ability to deal with unicode text strings.
4120 >>> hexenc("привет мир".encode("utf-8"))
4121 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
4122 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
4124 >>> s = UTF8String("привет мир")
4125 UTF8String UTF8String привет мир
4127 'привет мир'
4128 >>> hexenc(bytes(s))
4129 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
4131 >>> PrintableString("привет мир")
4132 Traceback (most recent call last):
4133 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
4135 >>> BMPString("ада", bounds=(2, 2))
4136 Traceback (most recent call last):
4137 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
4138 >>> s = BMPString("ад", bounds=(2, 2))
4141 >>> hexenc(bytes(s))
4149 * - :py:class:`pyderasn.UTF8String`
4151 * - :py:class:`pyderasn.NumericString`
4153 * - :py:class:`pyderasn.PrintableString`
4155 * - :py:class:`pyderasn.TeletexString`
4157 * - :py:class:`pyderasn.T61String`
4159 * - :py:class:`pyderasn.VideotexString`
4161 * - :py:class:`pyderasn.IA5String`
4163 * - :py:class:`pyderasn.GraphicString`
4165 * - :py:class:`pyderasn.VisibleString`
4167 * - :py:class:`pyderasn.ISO646String`
4169 * - :py:class:`pyderasn.GeneralString`
4171 * - :py:class:`pyderasn.UniversalString`
4173 * - :py:class:`pyderasn.BMPString`
4178 def _value_sanitize(self, value):
4180 value_decoded = None
4181 if isinstance(value, self.__class__):
4182 value_raw = value._value
4183 elif value.__class__ == text_type:
4184 value_decoded = value
4185 elif value.__class__ == binary_type:
4188 raise InvalidValueType((self.__class__, text_type, binary_type))
4191 value_decoded.encode(self.encoding)
4192 if value_raw is None else value_raw
4195 value_raw.decode(self.encoding)
4196 if value_decoded is None else value_decoded
4198 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4199 raise DecodeError(str(err))
4200 if not self._bound_min <= len(value_decoded) <= self._bound_max:
4208 def __eq__(self, their):
4209 if their.__class__ == binary_type:
4210 return self._value == their
4211 if their.__class__ == text_type:
4212 return self._value == their.encode(self.encoding)
4213 if not isinstance(their, self.__class__):
4216 self._value == their._value and
4217 self.tag == their.tag and
4218 self._expl == their._expl
4221 def __unicode__(self):
4223 return self._value.decode(self.encoding)
4224 return text_type(self._value)
4227 return pp_console_row(next(self.pps(no_unicode=PY2)))
4229 def pps(self, decode_path=(), no_unicode=False):
4233 hexenc(bytes(self)) if no_unicode else
4234 "".join(escape_control_unicode(c) for c in self.__unicode__())
4238 asn1_type_name=self.asn1_type_name,
4239 obj_name=self.__class__.__name__,
4240 decode_path=decode_path,
4242 optional=self.optional,
4243 default=self == self.default,
4244 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4245 expl=None if self._expl is None else tag_decode(self._expl),
4250 expl_offset=self.expl_offset if self.expled else None,
4251 expl_tlen=self.expl_tlen if self.expled else None,
4252 expl_llen=self.expl_llen if self.expled else None,
4253 expl_vlen=self.expl_vlen if self.expled else None,
4254 expl_lenindef=self.expl_lenindef,
4255 ber_encoded=self.ber_encoded,
4258 for pp in self.pps_lenindef(decode_path):
4262 class UTF8String(CommonString):
4264 tag_default = tag_encode(12)
4266 asn1_type_name = "UTF8String"
4269 class AllowableCharsMixin(object):
4271 def allowable_chars(self):
4273 return self._allowable_chars
4274 return frozenset(six_unichr(c) for c in self._allowable_chars)
4277 class NumericString(AllowableCharsMixin, CommonString):
4280 Its value is properly sanitized: only ASCII digits with spaces can
4283 >>> NumericString().allowable_chars
4284 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
4287 tag_default = tag_encode(18)
4289 asn1_type_name = "NumericString"
4290 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
4292 def _value_sanitize(self, value):
4293 value = super(NumericString, self)._value_sanitize(value)
4294 if not frozenset(value) <= self._allowable_chars:
4295 raise DecodeError("non-numeric value")
4299 PrintableStringState = namedtuple(
4300 "PrintableStringState",
4301 OctetStringState._fields + ("allowable_chars",),
4306 class PrintableString(AllowableCharsMixin, CommonString):
4309 Its value is properly sanitized: see X.680 41.4 table 10.
4311 >>> PrintableString().allowable_chars
4312 frozenset([' ', "'", ..., 'z'])
4313 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4314 PrintableString PrintableString foo*bar
4315 >>> obj.allow_asterisk, obj.allow_ampersand
4319 tag_default = tag_encode(19)
4321 asn1_type_name = "PrintableString"
4322 _allowable_chars = frozenset(
4323 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4325 _asterisk = frozenset("*".encode("ascii"))
4326 _ampersand = frozenset("&".encode("ascii"))
4338 allow_asterisk=False,
4339 allow_ampersand=False,
4342 :param allow_asterisk: allow asterisk character
4343 :param allow_ampersand: allow ampersand character
4346 self._allowable_chars |= self._asterisk
4348 self._allowable_chars |= self._ampersand
4349 super(PrintableString, self).__init__(
4350 value, bounds, impl, expl, default, optional, _decoded, ctx,
4354 def allow_asterisk(self):
4355 """Is asterisk character allowed?
4357 return self._asterisk <= self._allowable_chars
4360 def allow_ampersand(self):
4361 """Is ampersand character allowed?
4363 return self._ampersand <= self._allowable_chars
4365 def _value_sanitize(self, value):
4366 value = super(PrintableString, self)._value_sanitize(value)
4367 if not frozenset(value) <= self._allowable_chars:
4368 raise DecodeError("non-printable value")
4371 def __getstate__(self):
4372 return PrintableStringState(
4373 *super(PrintableString, self).__getstate__(),
4374 **{"allowable_chars": self._allowable_chars}
4377 def __setstate__(self, state):
4378 super(PrintableString, self).__setstate__(state)
4379 self._allowable_chars = state.allowable_chars
4390 return self.__class__(
4393 (self._bound_min, self._bound_max)
4394 if bounds is None else bounds
4396 impl=self.tag if impl is None else impl,
4397 expl=self._expl if expl is None else expl,
4398 default=self.default if default is None else default,
4399 optional=self.optional if optional is None else optional,
4400 allow_asterisk=self.allow_asterisk,
4401 allow_ampersand=self.allow_ampersand,
4405 class TeletexString(CommonString):
4407 tag_default = tag_encode(20)
4409 asn1_type_name = "TeletexString"
4412 class T61String(TeletexString):
4414 asn1_type_name = "T61String"
4417 class VideotexString(CommonString):
4419 tag_default = tag_encode(21)
4420 encoding = "iso-8859-1"
4421 asn1_type_name = "VideotexString"
4424 class IA5String(CommonString):
4426 tag_default = tag_encode(22)
4428 asn1_type_name = "IA5"
4431 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4432 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4433 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4436 class VisibleString(CommonString):
4438 tag_default = tag_encode(26)
4440 asn1_type_name = "VisibleString"
4443 UTCTimeState = namedtuple(
4445 OctetStringState._fields + ("ber_raw",),
4450 def str_to_time_fractions(value):
4452 year, v = (v // 10**10), (v % 10**10)
4453 month, v = (v // 10**8), (v % 10**8)
4454 day, v = (v // 10**6), (v % 10**6)
4455 hour, v = (v // 10**4), (v % 10**4)
4456 minute, second = (v // 100), (v % 100)
4457 return year, month, day, hour, minute, second
4460 class UTCTime(VisibleString):
4461 """``UTCTime`` datetime type
4463 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4464 UTCTime UTCTime 2017-09-30T22:07:50
4470 datetime.datetime(2017, 9, 30, 22, 7, 50)
4471 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4472 datetime.datetime(1957, 9, 30, 22, 7, 50)
4474 If BER encoded value was met, then ``ber_raw`` attribute will hold
4475 its raw representation.
4479 Pay attention that UTCTime can not hold full year, so all years
4480 having < 50 years are treated as 20xx, 19xx otherwise, according
4481 to X.509 recommendation.
4485 No strict validation of UTC offsets are made, but very crude:
4487 * minutes are not exceeding 60
4488 * offset value is not exceeding 14 hours
4490 __slots__ = ("ber_raw",)
4491 tag_default = tag_encode(23)
4493 asn1_type_name = "UTCTime"
4494 evgen_mode_skip_value = False
4504 bounds=None, # dummy argument, workability for OctetString.decode
4508 :param value: set the value. Either datetime type, or
4509 :py:class:`pyderasn.UTCTime` object
4510 :param bytes impl: override default tag with ``IMPLICIT`` one
4511 :param bytes expl: override default tag with ``EXPLICIT`` one
4512 :param default: set default value. Type same as in ``value``
4513 :param bool optional: is object ``OPTIONAL`` in sequence
4515 super(UTCTime, self).__init__(
4516 None, None, impl, expl, None, optional, _decoded, ctx,
4520 if value is not None:
4521 self._value, self.ber_raw = self._value_sanitize(value, ctx)
4522 self.ber_encoded = self.ber_raw is not None
4523 if default is not None:
4524 default, _ = self._value_sanitize(default)
4525 self.default = self.__class__(
4530 if self._value is None:
4531 self._value = default
4533 self.optional = optional
4535 def _strptime_bered(self, value):
4536 year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
4539 raise ValueError("no timezone")
4540 year += 2000 if year < 50 else 1900
4541 decoded = datetime(year, month, day, hour, minute)
4543 if value[-1] == "Z":
4547 raise ValueError("invalid UTC offset")
4548 if value[-5] == "-":
4550 elif value[-5] == "+":
4553 raise ValueError("invalid UTC offset")
4554 v = pureint(value[-4:])
4555 offset, v = (60 * (v % 100)), v // 100
4557 raise ValueError("invalid UTC offset minutes")
4559 if offset > 14 * 3600:
4560 raise ValueError("too big UTC offset")
4564 return offset, decoded
4566 raise ValueError("invalid UTC offset seconds")
4567 seconds = pureint(value)
4569 raise ValueError("invalid seconds value")
4570 return offset, decoded + timedelta(seconds=seconds)
4572 def _strptime(self, value):
4573 # datetime.strptime's format: %y%m%d%H%M%SZ
4574 if len(value) != LEN_YYMMDDHHMMSSZ:
4575 raise ValueError("invalid UTCTime length")
4576 if value[-1] != "Z":
4577 raise ValueError("non UTC timezone")
4578 year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
4579 year += 2000 if year < 50 else 1900
4580 return datetime(year, month, day, hour, minute, second)
4582 def _dt_sanitize(self, value):
4583 if value.year < 1950 or value.year > 2049:
4584 raise ValueError("UTCTime can hold only 1950-2049 years")
4585 return value.replace(microsecond=0)
4587 def _value_sanitize(self, value, ctx=None):
4588 if value.__class__ == binary_type:
4590 value_decoded = value.decode("ascii")
4591 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4592 raise DecodeError("invalid UTCTime encoding: %r" % err)
4595 return self._strptime(value_decoded), None
4596 except (TypeError, ValueError) as _err:
4598 if (ctx is not None) and ctx.get("bered", False):
4600 offset, _value = self._strptime_bered(value_decoded)
4601 _value = _value - timedelta(seconds=offset)
4602 return self._dt_sanitize(_value), value
4603 except (TypeError, ValueError, OverflowError) as _err:
4606 "invalid %s format: %r" % (self.asn1_type_name, err),
4607 klass=self.__class__,
4609 if isinstance(value, self.__class__):
4610 return value._value, None
4611 if value.__class__ == datetime:
4612 return self._dt_sanitize(value), None
4613 raise InvalidValueType((self.__class__, datetime))
4615 def _pp_value(self):
4617 value = self._value.isoformat()
4618 if self.ber_encoded:
4619 value += " (%s)" % self.ber_raw
4622 def __unicode__(self):
4624 value = self._value.isoformat()
4625 if self.ber_encoded:
4626 value += " (%s)" % self.ber_raw
4628 return text_type(self._pp_value())
4630 def __getstate__(self):
4631 return UTCTimeState(
4632 *super(UTCTime, self).__getstate__(),
4633 **{"ber_raw": self.ber_raw}
4636 def __setstate__(self, state):
4637 super(UTCTime, self).__setstate__(state)
4638 self.ber_raw = state.ber_raw
4640 def __bytes__(self):
4641 self._assert_ready()
4642 return self._encode_time()
4644 def __eq__(self, their):
4645 if their.__class__ == binary_type:
4646 return self._encode_time() == their
4647 if their.__class__ == datetime:
4648 return self.todatetime() == their
4649 if not isinstance(their, self.__class__):
4652 self._value == their._value and
4653 self.tag == their.tag and
4654 self._expl == their._expl
4657 def _encode_time(self):
4658 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4661 self._assert_ready()
4662 value = self._encode_time()
4663 return b"".join((self.tag, len_encode(len(value)), value))
4665 def _encode_cer(self, writer):
4666 write_full(writer, self._encode())
4668 def todatetime(self):
4672 return pp_console_row(next(self.pps()))
4674 def pps(self, decode_path=()):
4677 asn1_type_name=self.asn1_type_name,
4678 obj_name=self.__class__.__name__,
4679 decode_path=decode_path,
4680 value=self._pp_value(),
4681 optional=self.optional,
4682 default=self == self.default,
4683 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4684 expl=None if self._expl is None else tag_decode(self._expl),
4689 expl_offset=self.expl_offset if self.expled else None,
4690 expl_tlen=self.expl_tlen if self.expled else None,
4691 expl_llen=self.expl_llen if self.expled else None,
4692 expl_vlen=self.expl_vlen if self.expled else None,
4693 expl_lenindef=self.expl_lenindef,
4694 ber_encoded=self.ber_encoded,
4697 for pp in self.pps_lenindef(decode_path):
4701 class GeneralizedTime(UTCTime):
4702 """``GeneralizedTime`` datetime type
4704 This type is similar to :py:class:`pyderasn.UTCTime`.
4706 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4707 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4709 '20170930220750.000123Z'
4710 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4711 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4715 Only microsecond fractions are supported in DER encoding.
4716 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4717 higher precision values.
4721 BER encoded data can loss information (accuracy) during decoding
4722 because of float transformations.
4726 Local times (without explicit timezone specification) are treated
4727 as UTC one, no transformations are made.
4731 Zero year is unsupported.
4734 tag_default = tag_encode(24)
4735 asn1_type_name = "GeneralizedTime"
4737 def _dt_sanitize(self, value):
4740 def _strptime_bered(self, value):
4741 if len(value) < 4 + 3 * 2:
4742 raise ValueError("invalid GeneralizedTime")
4743 year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
4744 decoded = datetime(year, month, day, hour)
4745 offset, value = 0, value[10:]
4747 return offset, decoded
4748 if value[-1] == "Z":
4751 for char, sign in (("-", -1), ("+", 1)):
4752 idx = value.rfind(char)
4755 offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
4756 v = pureint(offset_raw)
4757 if len(offset_raw) == 4:
4758 offset, v = (60 * (v % 100)), v // 100
4760 raise ValueError("invalid UTC offset minutes")
4761 elif len(offset_raw) == 2:
4764 raise ValueError("invalid UTC offset")
4766 if offset > 14 * 3600:
4767 raise ValueError("too big UTC offset")
4771 return offset, decoded
4772 if value[0] in DECIMAL_SIGNS:
4774 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4777 raise ValueError("stripped minutes")
4778 decoded += timedelta(seconds=60 * pureint(value[:2]))
4781 return offset, decoded
4782 if value[0] in DECIMAL_SIGNS:
4784 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4787 raise ValueError("stripped seconds")
4788 decoded += timedelta(seconds=pureint(value[:2]))
4791 return offset, decoded
4792 if value[0] not in DECIMAL_SIGNS:
4793 raise ValueError("invalid format after seconds")
4795 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4798 def _strptime(self, value):
4800 if l == LEN_YYYYMMDDHHMMSSZ:
4801 # datetime.strptime's format: %Y%m%d%H%M%SZ
4802 if value[-1] != "Z":
4803 raise ValueError("non UTC timezone")
4804 return datetime(*str_to_time_fractions(value[:-1]))
4805 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4806 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4807 if value[-1] != "Z":
4808 raise ValueError("non UTC timezone")
4809 if value[14] != ".":
4810 raise ValueError("no fractions separator")
4813 raise ValueError("trailing zero")
4816 raise ValueError("only microsecond fractions are supported")
4817 us = pureint(us + ("0" * (6 - us_len)))
4818 year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
4819 return datetime(year, month, day, hour, minute, second, us)
4820 raise ValueError("invalid GeneralizedTime length")
4822 def _encode_time(self):
4824 encoded = value.strftime("%Y%m%d%H%M%S")
4825 if value.microsecond > 0:
4826 encoded += (".%06d" % value.microsecond).rstrip("0")
4827 return (encoded + "Z").encode("ascii")
4830 class GraphicString(CommonString):
4832 tag_default = tag_encode(25)
4833 encoding = "iso-8859-1"
4834 asn1_type_name = "GraphicString"
4837 class ISO646String(VisibleString):
4839 asn1_type_name = "ISO646String"
4842 class GeneralString(CommonString):
4844 tag_default = tag_encode(27)
4845 encoding = "iso-8859-1"
4846 asn1_type_name = "GeneralString"
4849 class UniversalString(CommonString):
4851 tag_default = tag_encode(28)
4852 encoding = "utf-32-be"
4853 asn1_type_name = "UniversalString"
4856 class BMPString(CommonString):
4858 tag_default = tag_encode(30)
4859 encoding = "utf-16-be"
4860 asn1_type_name = "BMPString"
4863 ChoiceState = namedtuple(
4865 BasicState._fields + ("specs", "value",),
4871 """``CHOICE`` special type
4875 class GeneralName(Choice):
4877 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4878 ("dNSName", IA5String(impl=tag_ctxp(2))),
4881 >>> gn = GeneralName()
4883 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4884 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4885 >>> gn["dNSName"] = IA5String("bar.baz")
4886 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4887 >>> gn["rfc822Name"]
4890 [2] IA5String IA5 bar.baz
4893 >>> gn.value == gn["dNSName"]
4896 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4898 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4899 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4901 __slots__ = ("specs",)
4903 asn1_type_name = "CHOICE"
4916 :param value: set the value. Either ``(choice, value)`` tuple, or
4917 :py:class:`pyderasn.Choice` object
4918 :param bytes impl: can not be set, do **not** use it
4919 :param bytes expl: override default tag with ``EXPLICIT`` one
4920 :param default: set default value. Type same as in ``value``
4921 :param bool optional: is object ``OPTIONAL`` in sequence
4923 if impl is not None:
4924 raise ValueError("no implicit tag allowed for CHOICE")
4925 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4927 schema = getattr(self, "schema", ())
4928 if len(schema) == 0:
4929 raise ValueError("schema must be specified")
4931 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
4934 if value is not None:
4935 self._value = self._value_sanitize(value)
4936 if default is not None:
4937 default_value = self._value_sanitize(default)
4938 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4939 default_obj.specs = self.specs
4940 default_obj._value = default_value
4941 self.default = default_obj
4943 self._value = copy(default_obj._value)
4944 if self._expl is not None:
4945 tag_class, _, tag_num = tag_decode(self._expl)
4946 self._tag_order = (tag_class, tag_num)
4948 def _value_sanitize(self, value):
4949 if (value.__class__ == tuple) and len(value) == 2:
4951 spec = self.specs.get(choice)
4953 raise ObjUnknown(choice)
4954 if not isinstance(obj, spec.__class__):
4955 raise InvalidValueType((spec,))
4956 return (choice, spec(obj))
4957 if isinstance(value, self.__class__):
4959 raise InvalidValueType((self.__class__, tuple))
4963 return self._value is not None and self._value[1].ready
4967 return self.expl_lenindef or (
4968 (self._value is not None) and
4969 self._value[1].bered
4972 def __getstate__(self):
4990 def __setstate__(self, state):
4991 super(Choice, self).__setstate__(state)
4992 self.specs = state.specs
4993 self._value = state.value
4995 def __eq__(self, their):
4996 if (their.__class__ == tuple) and len(their) == 2:
4997 return self._value == their
4998 if not isinstance(their, self.__class__):
5001 self.specs == their.specs and
5002 self._value == their._value
5012 return self.__class__(
5015 expl=self._expl if expl is None else expl,
5016 default=self.default if default is None else default,
5017 optional=self.optional if optional is None else optional,
5022 """Name of the choice
5024 self._assert_ready()
5025 return self._value[0]
5029 """Value of underlying choice
5031 self._assert_ready()
5032 return self._value[1]
5035 def tag_order(self):
5036 self._assert_ready()
5037 return self._value[1].tag_order if self._tag_order is None else self._tag_order
5040 def tag_order_cer(self):
5041 return min(v.tag_order_cer for v in itervalues(self.specs))
5043 def __getitem__(self, key):
5044 if key not in self.specs:
5045 raise ObjUnknown(key)
5046 if self._value is None:
5048 choice, value = self._value
5053 def __setitem__(self, key, value):
5054 spec = self.specs.get(key)
5056 raise ObjUnknown(key)
5057 if not isinstance(value, spec.__class__):
5058 raise InvalidValueType((spec.__class__,))
5059 self._value = (key, spec(value))
5067 return self._value[1].decoded if self.ready else False
5070 self._assert_ready()
5071 return self._value[1].encode()
5073 def _encode_cer(self, writer):
5074 self._assert_ready()
5075 self._value[1].encode_cer(writer)
5077 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5078 for choice, spec in iteritems(self.specs):
5079 sub_decode_path = decode_path + (choice,)
5085 decode_path=sub_decode_path,
5088 _ctx_immutable=False,
5095 klass=self.__class__,
5096 decode_path=decode_path,
5099 if tag_only: # pragma: no cover
5103 for _decode_path, value, tail in spec.decode_evgen(
5107 decode_path=sub_decode_path,
5109 _ctx_immutable=False,
5111 yield _decode_path, value, tail
5113 _, value, tail = next(spec.decode_evgen(
5117 decode_path=sub_decode_path,
5119 _ctx_immutable=False,
5122 obj = self.__class__(
5125 default=self.default,
5126 optional=self.optional,
5127 _decoded=(offset, 0, value.fulllen),
5129 obj._value = (choice, value)
5130 yield decode_path, obj, tail
5133 value = pp_console_row(next(self.pps()))
5135 value = "%s[%r]" % (value, self.value)
5138 def pps(self, decode_path=()):
5141 asn1_type_name=self.asn1_type_name,
5142 obj_name=self.__class__.__name__,
5143 decode_path=decode_path,
5144 value=self.choice if self.ready else None,
5145 optional=self.optional,
5146 default=self == self.default,
5147 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5148 expl=None if self._expl is None else tag_decode(self._expl),
5153 expl_lenindef=self.expl_lenindef,
5157 yield self.value.pps(decode_path=decode_path + (self.choice,))
5158 for pp in self.pps_lenindef(decode_path):
5162 class PrimitiveTypes(Choice):
5163 """Predefined ``CHOICE`` for all generic primitive types
5165 It could be useful for general decoding of some unspecified values:
5167 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
5168 OCTET STRING 3 bytes 666f6f
5169 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
5173 schema = tuple((klass.__name__, klass()) for klass in (
5197 AnyState = namedtuple(
5199 BasicState._fields + ("value", "defined"),
5205 """``ANY`` special type
5207 >>> Any(Integer(-123))
5208 ANY INTEGER -123 (0X:7B)
5209 >>> a = Any(OctetString(b"hello world").encode())
5210 ANY 040b68656c6c6f20776f726c64
5211 >>> hexenc(bytes(a))
5212 b'0x040x0bhello world'
5214 __slots__ = ("defined",)
5215 tag_default = tag_encode(0)
5216 asn1_type_name = "ANY"
5226 :param value: set the value. Either any kind of pyderasn's
5227 **ready** object, or bytes. Pay attention that
5228 **no** validation is performed if raw binary value
5229 is valid TLV, except just tag decoding
5230 :param bytes expl: override default tag with ``EXPLICIT`` one
5231 :param bool optional: is object ``OPTIONAL`` in sequence
5233 super(Any, self).__init__(None, expl, None, optional, _decoded)
5237 value = self._value_sanitize(value)
5239 if self._expl is None:
5240 if value.__class__ == binary_type:
5241 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5243 tag_class, tag_num = value.tag_order
5245 tag_class, _, tag_num = tag_decode(self._expl)
5246 self._tag_order = (tag_class, tag_num)
5249 def _value_sanitize(self, value):
5250 if value.__class__ == binary_type:
5252 raise ValueError("Any value can not be empty")
5254 if isinstance(value, self.__class__):
5256 if not isinstance(value, Obj):
5257 raise InvalidValueType((self.__class__, Obj, binary_type))
5262 return self._value is not None
5265 def tag_order(self):
5266 self._assert_ready()
5267 return self._tag_order
5271 if self.expl_lenindef or self.lenindef:
5273 if self.defined is None:
5275 return self.defined[1].bered
5277 def __getstate__(self):
5295 def __setstate__(self, state):
5296 super(Any, self).__setstate__(state)
5297 self._value = state.value
5298 self.defined = state.defined
5300 def __eq__(self, their):
5301 if their.__class__ == binary_type:
5302 if self._value.__class__ == binary_type:
5303 return self._value == their
5304 return self._value.encode() == their
5305 if issubclass(their.__class__, Any):
5306 if self.ready and their.ready:
5307 return bytes(self) == bytes(their)
5308 return self.ready == their.ready
5317 return self.__class__(
5319 expl=self._expl if expl is None else expl,
5320 optional=self.optional if optional is None else optional,
5323 def __bytes__(self):
5324 self._assert_ready()
5326 if value.__class__ == binary_type:
5328 return self._value.encode()
5335 self._assert_ready()
5337 if value.__class__ == binary_type:
5339 return value.encode()
5341 def _encode_cer(self, writer):
5342 self._assert_ready()
5344 if value.__class__ == binary_type:
5345 write_full(writer, value)
5347 value.encode_cer(writer)
5349 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5351 t, tlen, lv = tag_strip(tlv)
5352 except DecodeError as err:
5353 raise err.__class__(
5355 klass=self.__class__,
5356 decode_path=decode_path,
5360 l, llen, v = len_decode(lv)
5361 except LenIndefForm as err:
5362 if not ctx.get("bered", False):
5363 raise err.__class__(
5365 klass=self.__class__,
5366 decode_path=decode_path,
5369 llen, vlen, v = 1, 0, lv[1:]
5370 sub_offset = offset + tlen + llen
5372 while v[:EOC_LEN].tobytes() != EOC:
5373 chunk, v = Any().decode(
5376 decode_path=decode_path + (str(chunk_i),),
5379 _ctx_immutable=False,
5381 vlen += chunk.tlvlen
5382 sub_offset += chunk.tlvlen
5384 tlvlen = tlen + llen + vlen + EOC_LEN
5385 obj = self.__class__(
5386 value=None if evgen_mode else tlv[:tlvlen].tobytes(),
5388 optional=self.optional,
5389 _decoded=(offset, 0, tlvlen),
5392 obj.tag = t.tobytes()
5393 yield decode_path, obj, v[EOC_LEN:]
5395 except DecodeError as err:
5396 raise err.__class__(
5398 klass=self.__class__,
5399 decode_path=decode_path,
5403 raise NotEnoughData(
5404 "encoded length is longer than data",
5405 klass=self.__class__,
5406 decode_path=decode_path,
5409 tlvlen = tlen + llen + l
5410 v, tail = tlv[:tlvlen], v[l:]
5411 obj = self.__class__(
5412 value=None if evgen_mode else v.tobytes(),
5414 optional=self.optional,
5415 _decoded=(offset, 0, tlvlen),
5417 obj.tag = t.tobytes()
5418 yield decode_path, obj, tail
5421 return pp_console_row(next(self.pps()))
5423 def pps(self, decode_path=()):
5427 elif value.__class__ == binary_type:
5433 asn1_type_name=self.asn1_type_name,
5434 obj_name=self.__class__.__name__,
5435 decode_path=decode_path,
5437 blob=self._value if self._value.__class__ == binary_type else None,
5438 optional=self.optional,
5439 default=self == self.default,
5440 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5441 expl=None if self._expl is None else tag_decode(self._expl),
5446 expl_offset=self.expl_offset if self.expled else None,
5447 expl_tlen=self.expl_tlen if self.expled else None,
5448 expl_llen=self.expl_llen if self.expled else None,
5449 expl_vlen=self.expl_vlen if self.expled else None,
5450 expl_lenindef=self.expl_lenindef,
5451 lenindef=self.lenindef,
5454 defined_by, defined = self.defined or (None, None)
5455 if defined_by is not None:
5457 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5459 for pp in self.pps_lenindef(decode_path):
5463 ########################################################################
5464 # ASN.1 constructed types
5465 ########################################################################
5467 def get_def_by_path(defines_by_path, sub_decode_path):
5468 """Get define by decode path
5470 for path, define in defines_by_path:
5471 if len(path) != len(sub_decode_path):
5473 for p1, p2 in zip(path, sub_decode_path):
5474 if (not p1 is any) and (p1 != p2):
5480 def abs_decode_path(decode_path, rel_path):
5481 """Create an absolute decode path from current and relative ones
5483 :param decode_path: current decode path, starting point. Tuple of strings
5484 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5485 If first tuple's element is "/", then treat it as
5486 an absolute path, ignoring ``decode_path`` as
5487 starting point. Also this tuple can contain ".."
5488 elements, stripping the leading element from
5491 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5492 ("foo", "bar", "baz", "whatever")
5493 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5495 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5498 if rel_path[0] == "/":
5500 if rel_path[0] == "..":
5501 return abs_decode_path(decode_path[:-1], rel_path[1:])
5502 return decode_path + rel_path
5505 SequenceState = namedtuple(
5507 BasicState._fields + ("specs", "value",),
5512 class Sequence(Obj):
5513 """``SEQUENCE`` structure type
5515 You have to make specification of sequence::
5517 class Extension(Sequence):
5519 ("extnID", ObjectIdentifier()),
5520 ("critical", Boolean(default=False)),
5521 ("extnValue", OctetString()),
5524 Then, you can work with it as with dictionary.
5526 >>> ext = Extension()
5527 >>> Extension().specs
5529 ('extnID', OBJECT IDENTIFIER),
5530 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5531 ('extnValue', OCTET STRING),
5533 >>> ext["extnID"] = "1.2.3"
5534 Traceback (most recent call last):
5535 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5536 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5538 You can determine if sequence is ready to be encoded:
5543 Traceback (most recent call last):
5544 pyderasn.ObjNotReady: object is not ready: extnValue
5545 >>> ext["extnValue"] = OctetString(b"foobar")
5549 Value you want to assign, must have the same **type** as in
5550 corresponding specification, but it can have different tags,
5551 optional/default attributes -- they will be taken from specification
5554 class TBSCertificate(Sequence):
5556 ("version", Version(expl=tag_ctxc(0), default="v1")),
5559 >>> tbs = TBSCertificate()
5560 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5562 Assign ``None`` to remove value from sequence.
5564 You can set values in Sequence during its initialization:
5566 >>> AlgorithmIdentifier((
5567 ("algorithm", ObjectIdentifier("1.2.3")),
5568 ("parameters", Any(Null()))
5570 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5572 You can determine if value exists/set in the sequence and take its value:
5574 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5577 OBJECT IDENTIFIER 1.2.3
5579 But pay attention that if value has default, then it won't be (not
5580 in) in the sequence (because ``DEFAULT`` must not be encoded in
5581 DER), but you can read its value:
5583 >>> "critical" in ext, ext["critical"]
5584 (False, BOOLEAN False)
5585 >>> ext["critical"] = Boolean(True)
5586 >>> "critical" in ext, ext["critical"]
5587 (True, BOOLEAN True)
5589 All defaulted values are always optional.
5591 .. _allow_default_values_ctx:
5593 DER prohibits default value encoding and will raise an error if
5594 default value is unexpectedly met during decode.
5595 If :ref:`bered <bered_ctx>` context option is set, then no error
5596 will be raised, but ``bered`` attribute set. You can disable strict
5597 defaulted values existence validation by setting
5598 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5602 Check for default value existence is not performed in
5603 ``evgen_mode``, because previously decoded values are not stored
5604 in memory, to be able to compare them.
5606 Two sequences are equal if they have equal specification (schema),
5607 implicit/explicit tagging and the same values.
5609 __slots__ = ("specs",)
5610 tag_default = tag_encode(form=TagFormConstructed, num=16)
5611 asn1_type_name = "SEQUENCE"
5623 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5625 schema = getattr(self, "schema", ())
5627 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
5630 if value is not None:
5631 if issubclass(value.__class__, Sequence):
5632 self._value = value._value
5633 elif hasattr(value, "__iter__"):
5634 for seq_key, seq_value in value:
5635 self[seq_key] = seq_value
5637 raise InvalidValueType((Sequence,))
5638 if default is not None:
5639 if not issubclass(default.__class__, Sequence):
5640 raise InvalidValueType((Sequence,))
5641 default_value = default._value
5642 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5643 default_obj.specs = self.specs
5644 default_obj._value = default_value
5645 self.default = default_obj
5647 self._value = copy(default_obj._value)
5651 for name, spec in iteritems(self.specs):
5652 value = self._value.get(name)
5663 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5665 return any(value.bered for value in itervalues(self._value))
5667 def __getstate__(self):
5668 return SequenceState(
5682 {k: copy(v) for k, v in iteritems(self._value)},
5685 def __setstate__(self, state):
5686 super(Sequence, self).__setstate__(state)
5687 self.specs = state.specs
5688 self._value = state.value
5690 def __eq__(self, their):
5691 if not isinstance(their, self.__class__):
5694 self.specs == their.specs and
5695 self.tag == their.tag and
5696 self._expl == their._expl and
5697 self._value == their._value
5708 return self.__class__(
5711 impl=self.tag if impl is None else impl,
5712 expl=self._expl if expl is None else expl,
5713 default=self.default if default is None else default,
5714 optional=self.optional if optional is None else optional,
5717 def __contains__(self, key):
5718 return key in self._value
5720 def __setitem__(self, key, value):
5721 spec = self.specs.get(key)
5723 raise ObjUnknown(key)
5725 self._value.pop(key, None)
5727 if not isinstance(value, spec.__class__):
5728 raise InvalidValueType((spec.__class__,))
5729 value = spec(value=value)
5730 if spec.default is not None and value == spec.default:
5731 self._value.pop(key, None)
5733 self._value[key] = value
5735 def __getitem__(self, key):
5736 value = self._value.get(key)
5737 if value is not None:
5739 spec = self.specs.get(key)
5741 raise ObjUnknown(key)
5742 if spec.default is not None:
5746 def _values_for_encoding(self):
5747 for name, spec in iteritems(self.specs):
5748 value = self._value.get(name)
5752 raise ObjNotReady(name)
5756 v = b"".join(v.encode() for v in self._values_for_encoding())
5757 return b"".join((self.tag, len_encode(len(v)), v))
5759 def _encode_cer(self, writer):
5760 write_full(writer, self.tag + LENINDEF)
5761 for v in self._values_for_encoding():
5762 v.encode_cer(writer)
5763 write_full(writer, EOC)
5765 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5767 t, tlen, lv = tag_strip(tlv)
5768 except DecodeError as err:
5769 raise err.__class__(
5771 klass=self.__class__,
5772 decode_path=decode_path,
5777 klass=self.__class__,
5778 decode_path=decode_path,
5781 if tag_only: # pragma: no cover
5785 ctx_bered = ctx.get("bered", False)
5787 l, llen, v = len_decode(lv)
5788 except LenIndefForm as err:
5790 raise err.__class__(
5792 klass=self.__class__,
5793 decode_path=decode_path,
5796 l, llen, v = 0, 1, lv[1:]
5798 except DecodeError as err:
5799 raise err.__class__(
5801 klass=self.__class__,
5802 decode_path=decode_path,
5806 raise NotEnoughData(
5807 "encoded length is longer than data",
5808 klass=self.__class__,
5809 decode_path=decode_path,
5813 v, tail = v[:l], v[l:]
5815 sub_offset = offset + tlen + llen
5818 ctx_allow_default_values = ctx.get("allow_default_values", False)
5819 for name, spec in iteritems(self.specs):
5820 if spec.optional and (
5821 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5825 sub_decode_path = decode_path + (name,)
5828 for _decode_path, value, v_tail in spec.decode_evgen(
5832 decode_path=sub_decode_path,
5834 _ctx_immutable=False,
5836 yield _decode_path, value, v_tail
5838 _, value, v_tail = next(spec.decode_evgen(
5842 decode_path=sub_decode_path,
5844 _ctx_immutable=False,
5847 except TagMismatch as err:
5848 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5852 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5853 if not evgen_mode and defined is not None:
5854 defined_by, defined_spec = defined
5855 if issubclass(value.__class__, SequenceOf):
5856 for i, _value in enumerate(value):
5857 sub_sub_decode_path = sub_decode_path + (
5859 DecodePathDefBy(defined_by),
5861 defined_value, defined_tail = defined_spec.decode(
5862 memoryview(bytes(_value)),
5864 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5865 if value.expled else (value.tlen + value.llen)
5868 decode_path=sub_sub_decode_path,
5870 _ctx_immutable=False,
5872 if len(defined_tail) > 0:
5875 klass=self.__class__,
5876 decode_path=sub_sub_decode_path,
5879 _value.defined = (defined_by, defined_value)
5881 defined_value, defined_tail = defined_spec.decode(
5882 memoryview(bytes(value)),
5884 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5885 if value.expled else (value.tlen + value.llen)
5888 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5890 _ctx_immutable=False,
5892 if len(defined_tail) > 0:
5895 klass=self.__class__,
5896 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5899 value.defined = (defined_by, defined_value)
5901 value_len = value.fulllen
5903 sub_offset += value_len
5906 if spec.default is not None and value == spec.default:
5907 # This will not work in evgen_mode
5908 if ctx_bered or ctx_allow_default_values:
5912 "DEFAULT value met",
5913 klass=self.__class__,
5914 decode_path=sub_decode_path,
5917 values[name] = value
5918 spec_defines = getattr(spec, "defines", ())
5919 if len(spec_defines) == 0:
5920 defines_by_path = ctx.get("defines_by_path", ())
5921 if len(defines_by_path) > 0:
5922 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5923 if spec_defines is not None and len(spec_defines) > 0:
5924 for rel_path, schema in spec_defines:
5925 defined = schema.get(value, None)
5926 if defined is not None:
5927 ctx.setdefault("_defines", []).append((
5928 abs_decode_path(sub_decode_path[:-1], rel_path),
5932 if v[:EOC_LEN].tobytes() != EOC:
5935 klass=self.__class__,
5936 decode_path=decode_path,
5944 klass=self.__class__,
5945 decode_path=decode_path,
5948 obj = self.__class__(
5952 default=self.default,
5953 optional=self.optional,
5954 _decoded=(offset, llen, vlen),
5957 obj.lenindef = lenindef
5958 obj.ber_encoded = ber_encoded
5959 yield decode_path, obj, tail
5962 value = pp_console_row(next(self.pps()))
5964 for name in self.specs:
5965 _value = self._value.get(name)
5968 cols.append("%s: %s" % (name, repr(_value)))
5969 return "%s[%s]" % (value, "; ".join(cols))
5971 def pps(self, decode_path=()):
5974 asn1_type_name=self.asn1_type_name,
5975 obj_name=self.__class__.__name__,
5976 decode_path=decode_path,
5977 optional=self.optional,
5978 default=self == self.default,
5979 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5980 expl=None if self._expl is None else tag_decode(self._expl),
5985 expl_offset=self.expl_offset if self.expled else None,
5986 expl_tlen=self.expl_tlen if self.expled else None,
5987 expl_llen=self.expl_llen if self.expled else None,
5988 expl_vlen=self.expl_vlen if self.expled else None,
5989 expl_lenindef=self.expl_lenindef,
5990 lenindef=self.lenindef,
5991 ber_encoded=self.ber_encoded,
5994 for name in self.specs:
5995 value = self._value.get(name)
5998 yield value.pps(decode_path=decode_path + (name,))
5999 for pp in self.pps_lenindef(decode_path):
6003 class Set(Sequence):
6004 """``SET`` structure type
6006 Its usage is identical to :py:class:`pyderasn.Sequence`.
6008 .. _allow_unordered_set_ctx:
6010 DER prohibits unordered values encoding and will raise an error
6011 during decode. If :ref:`bered <bered_ctx>` context option is set,
6012 then no error will occur. Also you can disable strict values
6013 ordering check by setting ``"allow_unordered_set": True``
6014 :ref:`context <ctx>` option.
6017 tag_default = tag_encode(form=TagFormConstructed, num=17)
6018 asn1_type_name = "SET"
6021 v = b"".join(value.encode() for value in sorted(
6022 self._values_for_encoding(),
6023 key=attrgetter("tag_order"),
6025 return b"".join((self.tag, len_encode(len(v)), v))
6027 def _encode_cer(self, writer):
6028 write_full(writer, self.tag + LENINDEF)
6030 self._values_for_encoding(),
6031 key=attrgetter("tag_order_cer"),
6033 v.encode_cer(writer)
6034 write_full(writer, EOC)
6036 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
6038 t, tlen, lv = tag_strip(tlv)
6039 except DecodeError as err:
6040 raise err.__class__(
6042 klass=self.__class__,
6043 decode_path=decode_path,
6048 klass=self.__class__,
6049 decode_path=decode_path,
6056 ctx_bered = ctx.get("bered", False)
6058 l, llen, v = len_decode(lv)
6059 except LenIndefForm as err:
6061 raise err.__class__(
6063 klass=self.__class__,
6064 decode_path=decode_path,
6067 l, llen, v = 0, 1, lv[1:]
6069 except DecodeError as err:
6070 raise err.__class__(
6072 klass=self.__class__,
6073 decode_path=decode_path,
6077 raise NotEnoughData(
6078 "encoded length is longer than data",
6079 klass=self.__class__,
6083 v, tail = v[:l], v[l:]
6085 sub_offset = offset + tlen + llen
6088 ctx_allow_default_values = ctx.get("allow_default_values", False)
6089 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6090 tag_order_prev = (0, 0)
6091 _specs_items = copy(self.specs)
6094 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6096 for name, spec in iteritems(_specs_items):
6097 sub_decode_path = decode_path + (name,)
6103 decode_path=sub_decode_path,
6106 _ctx_immutable=False,
6113 klass=self.__class__,
6114 decode_path=decode_path,
6118 for _decode_path, value, v_tail in spec.decode_evgen(
6122 decode_path=sub_decode_path,
6124 _ctx_immutable=False,
6126 yield _decode_path, value, v_tail
6128 _, value, v_tail = next(spec.decode_evgen(
6132 decode_path=sub_decode_path,
6134 _ctx_immutable=False,
6137 value_tag_order = value.tag_order
6138 value_len = value.fulllen
6139 if tag_order_prev >= value_tag_order:
6140 if ctx_bered or ctx_allow_unordered_set:
6144 "unordered " + self.asn1_type_name,
6145 klass=self.__class__,
6146 decode_path=sub_decode_path,
6149 if spec.default is None or value != spec.default:
6151 elif ctx_bered or ctx_allow_default_values:
6155 "DEFAULT value met",
6156 klass=self.__class__,
6157 decode_path=sub_decode_path,
6160 values[name] = value
6161 del _specs_items[name]
6162 tag_order_prev = value_tag_order
6163 sub_offset += value_len
6167 obj = self.__class__(
6171 default=self.default,
6172 optional=self.optional,
6173 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6176 if v[:EOC_LEN].tobytes() != EOC:
6179 klass=self.__class__,
6180 decode_path=decode_path,
6185 for name, spec in iteritems(self.specs):
6186 if name not in values and not spec.optional:
6188 "%s value is not ready" % name,
6189 klass=self.__class__,
6190 decode_path=decode_path,
6195 obj.ber_encoded = ber_encoded
6196 yield decode_path, obj, tail
6199 SequenceOfState = namedtuple(
6201 BasicState._fields + ("spec", "value", "bound_min", "bound_max"),
6206 class SequenceOf(Obj):
6207 """``SEQUENCE OF`` sequence type
6209 For that kind of type you must specify the object it will carry on
6210 (bounds are for example here, not required)::
6212 class Ints(SequenceOf):
6217 >>> ints.append(Integer(123))
6218 >>> ints.append(Integer(234))
6220 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
6221 >>> [int(i) for i in ints]
6223 >>> ints.append(Integer(345))
6224 Traceback (most recent call last):
6225 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
6228 >>> ints[1] = Integer(345)
6230 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
6232 Also you can initialize sequence with preinitialized values:
6234 >>> ints = Ints([Integer(123), Integer(234)])
6236 __slots__ = ("spec", "_bound_min", "_bound_max")
6237 tag_default = tag_encode(form=TagFormConstructed, num=16)
6238 asn1_type_name = "SEQUENCE OF"
6251 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
6253 schema = getattr(self, "schema", None)
6255 raise ValueError("schema must be specified")
6257 self._bound_min, self._bound_max = getattr(
6261 ) if bounds is None else bounds
6263 if value is not None:
6264 self._value = self._value_sanitize(value)
6265 if default is not None:
6266 default_value = self._value_sanitize(default)
6267 default_obj = self.__class__(
6272 default_obj._value = default_value
6273 self.default = default_obj
6275 self._value = copy(default_obj._value)
6277 def _value_sanitize(self, value):
6278 if issubclass(value.__class__, SequenceOf):
6279 value = value._value
6280 elif hasattr(value, "__iter__"):
6283 raise InvalidValueType((self.__class__, iter))
6284 if not self._bound_min <= len(value) <= self._bound_max:
6285 raise BoundsError(self._bound_min, len(value), self._bound_max)
6287 if not isinstance(v, self.spec.__class__):
6288 raise InvalidValueType((self.spec.__class__,))
6293 return all(v.ready for v in self._value)
6297 if self.expl_lenindef or self.lenindef or self.ber_encoded:
6299 return any(v.bered for v in self._value)
6301 def __getstate__(self):
6302 return SequenceOfState(
6316 [copy(v) for v in self._value],
6321 def __setstate__(self, state):
6322 super(SequenceOf, self).__setstate__(state)
6323 self.spec = state.spec
6324 self._value = state.value
6325 self._bound_min = state.bound_min
6326 self._bound_max = state.bound_max
6328 def __eq__(self, their):
6329 if isinstance(their, self.__class__):
6331 self.spec == their.spec and
6332 self.tag == their.tag and
6333 self._expl == their._expl and
6334 self._value == their._value
6336 if hasattr(their, "__iter__"):
6337 return self._value == list(their)
6349 return self.__class__(
6353 (self._bound_min, self._bound_max)
6354 if bounds is None else bounds
6356 impl=self.tag if impl is None else impl,
6357 expl=self._expl if expl is None else expl,
6358 default=self.default if default is None else default,
6359 optional=self.optional if optional is None else optional,
6362 def __contains__(self, key):
6363 return key in self._value
6365 def append(self, value):
6366 if not isinstance(value, self.spec.__class__):
6367 raise InvalidValueType((self.spec.__class__,))
6368 if len(self._value) + 1 > self._bound_max:
6371 len(self._value) + 1,
6374 self._value.append(value)
6377 self._assert_ready()
6378 return iter(self._value)
6381 self._assert_ready()
6382 return len(self._value)
6384 def __setitem__(self, key, value):
6385 if not isinstance(value, self.spec.__class__):
6386 raise InvalidValueType((self.spec.__class__,))
6387 self._value[key] = self.spec(value=value)
6389 def __getitem__(self, key):
6390 return self._value[key]
6392 def _values_for_encoding(self):
6393 return iter(self._value)
6396 v = b"".join(v.encode() for v in self._values_for_encoding())
6397 return b"".join((self.tag, len_encode(len(v)), v))
6399 def _encode_cer(self, writer):
6400 write_full(writer, self.tag + LENINDEF)
6401 for v in self._values_for_encoding():
6402 v.encode_cer(writer)
6403 write_full(writer, EOC)
6413 ordering_check=False,
6416 t, tlen, lv = tag_strip(tlv)
6417 except DecodeError as err:
6418 raise err.__class__(
6420 klass=self.__class__,
6421 decode_path=decode_path,
6426 klass=self.__class__,
6427 decode_path=decode_path,
6434 ctx_bered = ctx.get("bered", False)
6436 l, llen, v = len_decode(lv)
6437 except LenIndefForm as err:
6439 raise err.__class__(
6441 klass=self.__class__,
6442 decode_path=decode_path,
6445 l, llen, v = 0, 1, lv[1:]
6447 except DecodeError as err:
6448 raise err.__class__(
6450 klass=self.__class__,
6451 decode_path=decode_path,
6455 raise NotEnoughData(
6456 "encoded length is longer than data",
6457 klass=self.__class__,
6458 decode_path=decode_path,
6462 v, tail = v[:l], v[l:]
6464 sub_offset = offset + tlen + llen
6467 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6468 value_prev = memoryview(v[:0])
6472 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6474 sub_decode_path = decode_path + (str(_value_count),)
6476 for _decode_path, value, v_tail in spec.decode_evgen(
6480 decode_path=sub_decode_path,
6482 _ctx_immutable=False,
6484 yield _decode_path, value, v_tail
6486 _, value, v_tail = next(spec.decode_evgen(
6490 decode_path=sub_decode_path,
6492 _ctx_immutable=False,
6495 value_len = value.fulllen
6497 if value_prev.tobytes() > v[:value_len].tobytes():
6498 if ctx_bered or ctx_allow_unordered_set:
6502 "unordered " + self.asn1_type_name,
6503 klass=self.__class__,
6504 decode_path=sub_decode_path,
6507 value_prev = v[:value_len]
6510 _value.append(value)
6511 sub_offset += value_len
6514 if evgen_mode and not self._bound_min <= _value_count <= self._bound_max:
6516 msg=str(BoundsError(self._bound_min, _value_count, self._bound_max)),
6517 klass=self.__class__,
6518 decode_path=decode_path,
6522 obj = self.__class__(
6523 value=None if evgen_mode else _value,
6525 bounds=(self._bound_min, self._bound_max),
6528 default=self.default,
6529 optional=self.optional,
6530 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6532 except BoundsError as err:
6535 klass=self.__class__,
6536 decode_path=decode_path,
6540 if v[:EOC_LEN].tobytes() != EOC:
6543 klass=self.__class__,
6544 decode_path=decode_path,
6549 obj.ber_encoded = ber_encoded
6550 yield decode_path, obj, tail
6554 pp_console_row(next(self.pps())),
6555 ", ".join(repr(v) for v in self._value),
6558 def pps(self, decode_path=()):
6561 asn1_type_name=self.asn1_type_name,
6562 obj_name=self.__class__.__name__,
6563 decode_path=decode_path,
6564 optional=self.optional,
6565 default=self == self.default,
6566 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6567 expl=None if self._expl is None else tag_decode(self._expl),
6572 expl_offset=self.expl_offset if self.expled else None,
6573 expl_tlen=self.expl_tlen if self.expled else None,
6574 expl_llen=self.expl_llen if self.expled else None,
6575 expl_vlen=self.expl_vlen if self.expled else None,
6576 expl_lenindef=self.expl_lenindef,
6577 lenindef=self.lenindef,
6578 ber_encoded=self.ber_encoded,
6581 for i, value in enumerate(self._value):
6582 yield value.pps(decode_path=decode_path + (str(i),))
6583 for pp in self.pps_lenindef(decode_path):
6587 class SetOf(SequenceOf):
6588 """``SET OF`` sequence type
6590 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6593 tag_default = tag_encode(form=TagFormConstructed, num=17)
6594 asn1_type_name = "SET OF"
6597 v = b"".join(sorted(v.encode() for v in self._values_for_encoding()))
6598 return b"".join((self.tag, len_encode(len(v)), v))
6600 def _encode_cer(self, writer):
6601 write_full(writer, self.tag + LENINDEF)
6602 for v in sorted(encode_cer(v) for v in self._values_for_encoding()):
6603 write_full(writer, v)
6604 write_full(writer, EOC)
6606 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
6607 return super(SetOf, self)._decode(
6614 ordering_check=True,
6618 def obj_by_path(pypath): # pragma: no cover
6619 """Import object specified as string Python path
6621 Modules must be separated from classes/functions with ``:``.
6623 >>> obj_by_path("foo.bar:Baz")
6624 <class 'foo.bar.Baz'>
6625 >>> obj_by_path("foo.bar:Baz.boo")
6626 <classmethod 'foo.bar.Baz.boo'>
6628 mod, objs = pypath.rsplit(":", 1)
6629 from importlib import import_module
6630 obj = import_module(mod)
6631 for obj_name in objs.split("."):
6632 obj = getattr(obj, obj_name)
6636 def generic_decoder(): # pragma: no cover
6637 # All of this below is a big hack with self references
6638 choice = PrimitiveTypes()
6639 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6640 choice.specs["SetOf"] = SetOf(schema=choice)
6641 for i in six_xrange(31):
6642 choice.specs["SequenceOf%d" % i] = SequenceOf(
6646 choice.specs["Any"] = Any()
6648 # Class name equals to type name, to omit it from output
6649 class SEQUENCEOF(SequenceOf):
6657 with_decode_path=False,
6658 decode_path_only=(),
6660 def _pprint_pps(pps):
6662 if hasattr(pp, "_fields"):
6664 decode_path_only != () and
6665 pp.decode_path[:len(decode_path_only)] != decode_path_only
6668 if pp.asn1_type_name == Choice.asn1_type_name:
6670 pp_kwargs = pp._asdict()
6671 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6672 pp = _pp(**pp_kwargs)
6673 yield pp_console_row(
6678 with_colours=with_colours,
6679 with_decode_path=with_decode_path,
6680 decode_path_len_decrease=len(decode_path_only),
6682 for row in pp_console_blob(
6684 decode_path_len_decrease=len(decode_path_only),
6688 for row in _pprint_pps(pp):
6690 return "\n".join(_pprint_pps(obj.pps()))
6691 return SEQUENCEOF(), pprint_any
6694 def main(): # pragma: no cover
6696 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6697 parser.add_argument(
6701 help="Skip that number of bytes from the beginning",
6703 parser.add_argument(
6705 help="Python paths to dictionary with OIDs, comma separated",
6707 parser.add_argument(
6709 help="Python path to schema definition to use",
6711 parser.add_argument(
6712 "--defines-by-path",
6713 help="Python path to decoder's defines_by_path",
6715 parser.add_argument(
6717 action="store_true",
6718 help="Disallow BER encoding",
6720 parser.add_argument(
6721 "--print-decode-path",
6722 action="store_true",
6723 help="Print decode paths",
6725 parser.add_argument(
6726 "--decode-path-only",
6727 help="Print only specified decode path",
6729 parser.add_argument(
6731 action="store_true",
6732 help="Allow explicit tag out-of-bound",
6734 parser.add_argument(
6736 action="store_true",
6737 help="Turn on event generation mode",
6739 parser.add_argument(
6741 type=argparse.FileType("rb"),
6742 help="Path to BER/CER/DER file you want to decode",
6744 args = parser.parse_args()
6746 args.RAWFile.seek(args.skip)
6747 raw = memoryview(args.RAWFile.read())
6748 args.RAWFile.close()
6750 raw = file_mmaped(args.RAWFile)[args.skip:]
6752 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6753 if args.oids else ()
6756 schema = obj_by_path(args.schema)
6757 from functools import partial
6758 pprinter = partial(pprint, big_blobs=True)
6760 schema, pprinter = generic_decoder()
6762 "bered": not args.nobered,
6763 "allow_expl_oob": args.allow_expl_oob,
6765 if args.defines_by_path is not None:
6766 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6767 from os import environ
6771 with_colours=environ.get("NO_COLOR") is None,
6772 with_decode_path=args.print_decode_path,
6774 () if args.decode_path_only is None else
6775 tuple(args.decode_path_only.split(":"))
6779 for decode_path, obj, tail in schema().decode_evgen(raw, ctx=ctx):
6780 print(pprinter(obj, decode_path=decode_path))
6782 obj, tail = schema().decode(raw, ctx=ctx)
6783 print(pprinter(obj))
6785 print("\nTrailing data: %s" % hexenc(tail))
6788 if __name__ == "__main__":