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.hexenc
648 .. autofunction:: pyderasn.hexdec
649 .. autofunction:: pyderasn.tag_encode
650 .. autofunction:: pyderasn.tag_decode
651 .. autofunction:: pyderasn.tag_ctxp
652 .. autofunction:: pyderasn.tag_ctxc
653 .. autoclass:: pyderasn.DecodeError
655 .. autoclass:: pyderasn.NotEnoughData
656 .. autoclass:: pyderasn.ExceedingData
657 .. autoclass:: pyderasn.LenIndefForm
658 .. autoclass:: pyderasn.TagMismatch
659 .. autoclass:: pyderasn.InvalidLength
660 .. autoclass:: pyderasn.InvalidOID
661 .. autoclass:: pyderasn.ObjUnknown
662 .. autoclass:: pyderasn.ObjNotReady
663 .. autoclass:: pyderasn.InvalidValueType
664 .. autoclass:: pyderasn.BoundsError
671 You can decode DER/BER files using command line abilities::
673 $ python -m pyderasn --schema tests.test_crts:Certificate path/to/file
675 If there is no schema for your file, then you can try parsing it without,
676 but of course IMPLICIT tags will often make it impossible. But result is
677 good enough for the certificate above::
679 $ python -m pyderasn path/to/file
680 0 [1,3,1604] . >: SEQUENCE OF
681 4 [1,3,1453] . . >: SEQUENCE OF
682 8 [0,0, 5] . . . . >: [0] ANY
683 . . . . . A0:03:02:01:02
684 13 [1,1, 3] . . . . >: INTEGER 61595
685 18 [1,1, 13] . . . . >: SEQUENCE OF
686 20 [1,1, 9] . . . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
687 31 [1,1, 0] . . . . . . >: NULL
688 33 [1,3, 274] . . . . >: SEQUENCE OF
689 37 [1,1, 11] . . . . . . >: SET OF
690 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
691 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER 2.5.4.6
692 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
694 1409 [1,1, 50] . . . . . . >: SEQUENCE OF
695 1411 [1,1, 8] . . . . . . . . >: OBJECT IDENTIFIER 1.3.6.1.5.5.7.1.1
696 1421 [1,1, 38] . . . . . . . . >: OCTET STRING 38 bytes
697 . . . . . . . . . 30:24:30:22:06:08:2B:06:01:05:05:07:30:01:86:16
698 . . . . . . . . . 68:74:74:70:3A:2F:2F:6F:63:73:70:2E:69:70:73:63
699 . . . . . . . . . 61:2E:63:6F:6D:2F
700 1461 [1,1, 13] . . >: SEQUENCE OF
701 1463 [1,1, 9] . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
702 1474 [1,1, 0] . . . . >: NULL
703 1476 [1,2, 129] . . >: BIT STRING 1024 bits
704 . . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
705 . . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
711 If you have got dictionaries with ObjectIdentifiers, like example one
712 from ``tests/test_crts.py``::
715 "1.2.840.113549.1.1.1": "id-rsaEncryption",
716 "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
718 "2.5.4.10": "id-at-organizationName",
719 "2.5.4.11": "id-at-organizationalUnitName",
722 then you can pass it to pretty printer to see human readable OIDs::
724 $ python -m pyderasn --oids tests.test_crts:stroid2name path/to/file
726 37 [1,1, 11] . . . . . . >: SET OF
727 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
728 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
729 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
730 50 [1,1, 18] . . . . . . >: SET OF
731 52 [1,1, 16] . . . . . . . . >: SEQUENCE OF
732 54 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
733 59 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
734 70 [1,1, 18] . . . . . . >: SET OF
735 72 [1,1, 16] . . . . . . . . >: SEQUENCE OF
736 74 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
737 79 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
743 Each decoded element has so-called decode path: sequence of structure
744 names it is passing during the decode process. Each element has its own
745 unique path inside the whole ASN.1 tree. You can print it out with
746 ``--print-decode-path`` option::
748 $ python -m pyderasn --schema path.to:Certificate --print-decode-path path/to/file
749 0 [1,3,1604] Certificate SEQUENCE []
750 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE [tbsCertificate]
751 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL [tbsCertificate:version]
752 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595 [tbsCertificate:serialNumber]
753 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE [tbsCertificate:signature]
754 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5 [tbsCertificate:signature:algorithm]
755 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL [tbsCertificate:signature:parameters]
757 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence [tbsCertificate:issuer]
758 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF [tbsCertificate:issuer:rdnSequence]
759 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF [tbsCertificate:issuer:rdnSequence:0]
760 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE [tbsCertificate:issuer:rdnSequence:0:0]
761 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6 [tbsCertificate:issuer:rdnSequence:0:0:type]
762 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY [tbsCertificate:issuer:rdnSequence:0:0:value]
763 . . . . . . . 13:02:45:53
764 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]
767 Now you can print only the specified tree, for example signature algorithm::
769 $ python -m pyderasn --schema path.to:Certificate --decode-path-only tbsCertificate:signature path/to/file
770 18 [1,1, 13] AlgorithmIdentifier SEQUENCE
771 20 [1,1, 9] . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
772 31 [0,0, 2] . parameters: [UNIV 5] ANY OPTIONAL
776 from codecs import getdecoder
777 from codecs import getencoder
778 from collections import namedtuple
779 from collections import OrderedDict
780 from copy import copy
781 from datetime import datetime
782 from datetime import timedelta
783 from io import BytesIO
784 from math import ceil
785 from operator import attrgetter
786 from string import ascii_letters
787 from string import digits
788 from sys import version_info
789 from unicodedata import category as unicat
791 from six import add_metaclass
792 from six import binary_type
793 from six import byte2int
794 from six import indexbytes
795 from six import int2byte
796 from six import integer_types
797 from six import iterbytes
798 from six import iteritems
799 from six import itervalues
801 from six import string_types
802 from six import text_type
803 from six import unichr as six_unichr
804 from six.moves import xrange as six_xrange
808 from termcolor import colored
809 except ImportError: # pragma: no cover
810 def colored(what, *args, **kwargs):
857 "TagClassApplication",
861 "TagFormConstructed",
872 TagClassUniversal = 0
873 TagClassApplication = 1 << 6
874 TagClassContext = 1 << 7
875 TagClassPrivate = 1 << 6 | 1 << 7
877 TagFormConstructed = 1 << 5
880 TagClassApplication: "APPLICATION ",
881 TagClassPrivate: "PRIVATE ",
882 TagClassUniversal: "UNIV ",
886 LENINDEF = b"\x80" # length indefinite mark
887 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
888 NAMEDTUPLE_KWARGS = {} if version_info < (3, 6) else {"module": __name__}
889 SET01 = frozenset("01")
890 DECIMALS = frozenset(digits)
895 if not set(value) <= DECIMALS:
896 raise ValueError("non-pure integer")
899 def fractions2float(fractions_raw):
900 pureint(fractions_raw)
901 return float("0." + fractions_raw)
904 def get_def_by_path(defines_by_path, sub_decode_path):
905 """Get define by decode path
907 for path, define in defines_by_path:
908 if len(path) != len(sub_decode_path):
910 for p1, p2 in zip(path, sub_decode_path):
911 if (not p1 is any) and (p1 != p2):
917 ########################################################################
919 ########################################################################
921 class ASN1Error(ValueError):
925 class DecodeError(ASN1Error):
926 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
928 :param str msg: reason of decode failing
929 :param klass: optional exact DecodeError inherited class (like
930 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
931 :py:exc:`InvalidLength`)
932 :param decode_path: tuple of strings. It contains human
933 readable names of the fields through which
934 decoding process has passed
935 :param int offset: binary offset where failure happened
937 super(DecodeError, self).__init__()
940 self.decode_path = decode_path
946 "" if self.klass is None else self.klass.__name__,
948 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
949 if len(self.decode_path) > 0 else ""
951 ("(at %d)" % self.offset) if self.offset > 0 else "",
957 return "%s(%s)" % (self.__class__.__name__, self)
960 class NotEnoughData(DecodeError):
964 class ExceedingData(ASN1Error):
965 def __init__(self, nbytes):
966 super(ExceedingData, self).__init__()
970 return "%d trailing bytes" % self.nbytes
973 return "%s(%s)" % (self.__class__.__name__, self)
976 class LenIndefForm(DecodeError):
980 class TagMismatch(DecodeError):
984 class InvalidLength(DecodeError):
988 class InvalidOID(DecodeError):
992 class ObjUnknown(ASN1Error):
993 def __init__(self, name):
994 super(ObjUnknown, self).__init__()
998 return "object is unknown: %s" % self.name
1001 return "%s(%s)" % (self.__class__.__name__, self)
1004 class ObjNotReady(ASN1Error):
1005 def __init__(self, name):
1006 super(ObjNotReady, self).__init__()
1010 return "object is not ready: %s" % self.name
1013 return "%s(%s)" % (self.__class__.__name__, self)
1016 class InvalidValueType(ASN1Error):
1017 def __init__(self, expected_types):
1018 super(InvalidValueType, self).__init__()
1019 self.expected_types = expected_types
1022 return "invalid value type, expected: %s" % ", ".join(
1023 [repr(t) for t in self.expected_types]
1027 return "%s(%s)" % (self.__class__.__name__, self)
1030 class BoundsError(ASN1Error):
1031 def __init__(self, bound_min, value, bound_max):
1032 super(BoundsError, self).__init__()
1033 self.bound_min = bound_min
1035 self.bound_max = bound_max
1038 return "unsatisfied bounds: %s <= %s <= %s" % (
1045 return "%s(%s)" % (self.__class__.__name__, self)
1048 ########################################################################
1050 ########################################################################
1052 _hexdecoder = getdecoder("hex")
1053 _hexencoder = getencoder("hex")
1057 """Binary data to hexadecimal string convert
1059 return _hexdecoder(data)[0]
1063 """Hexadecimal string to binary data convert
1065 return _hexencoder(data)[0].decode("ascii")
1068 def int_bytes_len(num, byte_len=8):
1071 return int(ceil(float(num.bit_length()) / byte_len))
1074 def zero_ended_encode(num):
1075 octets = bytearray(int_bytes_len(num, 7))
1077 octets[i] = num & 0x7F
1081 octets[i] = 0x80 | (num & 0x7F)
1084 return bytes(octets)
1087 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
1088 """Encode tag to binary form
1090 :param int num: tag's number
1091 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
1092 :py:data:`pyderasn.TagClassContext`,
1093 :py:data:`pyderasn.TagClassApplication`,
1094 :py:data:`pyderasn.TagClassPrivate`)
1095 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
1096 :py:data:`pyderasn.TagFormConstructed`)
1100 return int2byte(klass | form | num)
1101 # [XX|X|11111][1.......][1.......] ... [0.......]
1102 return int2byte(klass | form | 31) + zero_ended_encode(num)
1105 def tag_decode(tag):
1106 """Decode tag from binary form
1110 No validation is performed, assuming that it has already passed.
1112 It returns tuple with three integers, as
1113 :py:func:`pyderasn.tag_encode` accepts.
1115 first_octet = byte2int(tag)
1116 klass = first_octet & 0xC0
1117 form = first_octet & 0x20
1118 if first_octet & 0x1F < 0x1F:
1119 return (klass, form, first_octet & 0x1F)
1121 for octet in iterbytes(tag[1:]):
1124 return (klass, form, num)
1128 """Create CONTEXT PRIMITIVE tag
1130 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
1134 """Create CONTEXT CONSTRUCTED tag
1136 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
1139 def tag_strip(data):
1140 """Take off tag from the data
1142 :returns: (encoded tag, tag length, remaining data)
1145 raise NotEnoughData("no data at all")
1146 if byte2int(data) & 0x1F < 31:
1147 return data[:1], 1, data[1:]
1152 raise DecodeError("unfinished tag")
1153 if indexbytes(data, i) & 0x80 == 0:
1156 return data[:i], i, data[i:]
1162 octets = bytearray(int_bytes_len(l) + 1)
1163 octets[0] = 0x80 | (len(octets) - 1)
1164 for i in six_xrange(len(octets) - 1, 0, -1):
1165 octets[i] = l & 0xFF
1167 return bytes(octets)
1170 def len_decode(data):
1173 :returns: (decoded length, length's length, remaining data)
1174 :raises LenIndefForm: if indefinite form encoding is met
1177 raise NotEnoughData("no data at all")
1178 first_octet = byte2int(data)
1179 if first_octet & 0x80 == 0:
1180 return first_octet, 1, data[1:]
1181 octets_num = first_octet & 0x7F
1182 if octets_num + 1 > len(data):
1183 raise NotEnoughData("encoded length is longer than data")
1185 raise LenIndefForm()
1186 if byte2int(data[1:]) == 0:
1187 raise DecodeError("leading zeros")
1189 for v in iterbytes(data[1:1 + octets_num]):
1192 raise DecodeError("long form instead of short one")
1193 return l, 1 + octets_num, data[1 + octets_num:]
1196 LEN1K = len_encode(1000)
1199 def write_full(writer, data):
1200 """Fully write provided data
1202 BytesIO does not guarantee that the whole data will be written at once.
1204 data = memoryview(data)
1206 while written != len(data):
1207 n = writer(data[written:])
1209 raise ValueError("can not write to buf")
1213 ########################################################################
1215 ########################################################################
1217 class AutoAddSlots(type):
1218 def __new__(cls, name, bases, _dict):
1219 _dict["__slots__"] = _dict.get("__slots__", ())
1220 return type.__new__(cls, name, bases, _dict)
1223 BasicState = namedtuple("BasicState", (
1236 ), **NAMEDTUPLE_KWARGS)
1239 @add_metaclass(AutoAddSlots)
1241 """Common ASN.1 object class
1243 All ASN.1 types are inherited from it. It has metaclass that
1244 automatically adds ``__slots__`` to all inherited classes.
1269 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1270 self._expl = getattr(self, "expl", None) if expl is None else expl
1271 if self.tag != self.tag_default and self._expl is not None:
1272 raise ValueError("implicit and explicit tags can not be set simultaneously")
1273 if self.tag is None:
1274 self._tag_order = None
1276 tag_class, _, tag_num = tag_decode(
1277 self.tag if self._expl is None else self._expl
1279 self._tag_order = (tag_class, tag_num)
1280 if default is not None:
1282 self.optional = optional
1283 self.offset, self.llen, self.vlen = _decoded
1285 self.expl_lenindef = False
1286 self.lenindef = False
1287 self.ber_encoded = False
1290 def ready(self): # pragma: no cover
1291 """Is object ready to be encoded?
1293 raise NotImplementedError()
1295 def _assert_ready(self):
1297 raise ObjNotReady(self.__class__.__name__)
1301 """Is either object or any elements inside is BER encoded?
1303 return self.expl_lenindef or self.lenindef or self.ber_encoded
1307 """Is object decoded?
1309 return (self.llen + self.vlen) > 0
1311 def __getstate__(self): # pragma: no cover
1312 """Used for making safe to be mutable pickleable copies
1314 raise NotImplementedError()
1316 def __setstate__(self, state):
1317 if state.version != __version__:
1318 raise ValueError("data is pickled by different PyDERASN version")
1319 self.tag = state.tag
1320 self._tag_order = state.tag_order
1321 self._expl = state.expl
1322 self.default = state.default
1323 self.optional = state.optional
1324 self.offset = state.offset
1325 self.llen = state.llen
1326 self.vlen = state.vlen
1327 self.expl_lenindef = state.expl_lenindef
1328 self.lenindef = state.lenindef
1329 self.ber_encoded = state.ber_encoded
1332 def tag_order(self):
1333 """Tag's (class, number) used for DER/CER sorting
1335 return self._tag_order
1338 def tag_order_cer(self):
1339 return self.tag_order
1343 """See :ref:`decoding`
1345 return len(self.tag)
1349 """See :ref:`decoding`
1351 return self.tlen + self.llen + self.vlen
1353 def __str__(self): # pragma: no cover
1354 return self.__bytes__() if PY2 else self.__unicode__()
1356 def __ne__(self, their):
1357 return not(self == their)
1359 def __gt__(self, their): # pragma: no cover
1360 return not(self < their)
1362 def __le__(self, their): # pragma: no cover
1363 return (self == their) or (self < their)
1365 def __ge__(self, their): # pragma: no cover
1366 return (self == their) or (self > their)
1368 def _encode(self): # pragma: no cover
1369 raise NotImplementedError()
1371 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode): # pragma: no cover
1372 yield NotImplemented
1375 """Encode the structure
1377 :returns: DER representation
1379 raw = self._encode()
1380 if self._expl is None:
1382 return b"".join((self._expl, len_encode(len(raw)), raw))
1384 def encode_cer(self, writer):
1385 if self._expl is not None:
1386 write_full(writer, self._expl + LENINDEF)
1387 if getattr(self, "der_forced", False):
1388 write_full(writer, self._encode())
1390 self._encode_cer(writer)
1391 if self._expl is not None:
1392 write_full(writer, EOC)
1394 def _encode_cer(self, writer):
1395 write_full(writer, self._encode())
1397 def hexencode(self):
1398 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1400 return hexenc(self.encode())
1410 _ctx_immutable=True,
1412 result = next(self.decode_evgen(
1424 _, obj, tail = result
1435 _ctx_immutable=True,
1440 :param data: either binary or memoryview
1441 :param int offset: initial data's offset
1442 :param bool leavemm: do we need to leave memoryview of remaining
1443 data as is, or convert it to bytes otherwise
1444 :param ctx: optional :ref:`context <ctx>` governing decoding process
1445 :param tag_only: decode only the tag, without length and contents
1446 (used only in Choice and Set structures, trying to
1447 determine if tag satisfies the schema)
1448 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1450 :returns: (Obj, remaining data)
1452 .. seealso:: :ref:`decoding`
1456 elif _ctx_immutable:
1458 tlv = memoryview(data)
1461 get_def_by_path(ctx.get("evgen_mode_upto", ()), decode_path) is not None
1464 if self._expl is None:
1465 for result in self._decode(
1468 decode_path=decode_path,
1471 evgen_mode=_evgen_mode,
1476 _decode_path, obj, tail = result
1477 if not _decode_path is decode_path:
1481 t, tlen, lv = tag_strip(tlv)
1482 except DecodeError as err:
1483 raise err.__class__(
1485 klass=self.__class__,
1486 decode_path=decode_path,
1491 klass=self.__class__,
1492 decode_path=decode_path,
1496 l, llen, v = len_decode(lv)
1497 except LenIndefForm as err:
1498 if not ctx.get("bered", False):
1499 raise err.__class__(
1501 klass=self.__class__,
1502 decode_path=decode_path,
1506 offset += tlen + llen
1507 for result in self._decode(
1510 decode_path=decode_path,
1513 evgen_mode=_evgen_mode,
1515 if tag_only: # pragma: no cover
1518 _decode_path, obj, tail = result
1519 if not _decode_path is decode_path:
1521 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1522 if eoc_expected.tobytes() != EOC:
1525 klass=self.__class__,
1526 decode_path=decode_path,
1530 obj.expl_lenindef = True
1531 except DecodeError as err:
1532 raise err.__class__(
1534 klass=self.__class__,
1535 decode_path=decode_path,
1540 raise NotEnoughData(
1541 "encoded length is longer than data",
1542 klass=self.__class__,
1543 decode_path=decode_path,
1546 for result in self._decode(
1548 offset=offset + tlen + llen,
1549 decode_path=decode_path,
1552 evgen_mode=_evgen_mode,
1554 if tag_only: # pragma: no cover
1557 _decode_path, obj, tail = result
1558 if not _decode_path is decode_path:
1560 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1562 "explicit tag out-of-bound, longer than data",
1563 klass=self.__class__,
1564 decode_path=decode_path,
1567 yield decode_path, obj, (tail if leavemm else tail.tobytes())
1569 def decod(self, data, offset=0, decode_path=(), ctx=None):
1570 """Decode the data, check that tail is empty
1572 :raises ExceedingData: if tail is not empty
1574 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1575 (decode without tail) that also checks that there is no
1578 obj, tail = self.decode(
1581 decode_path=decode_path,
1586 raise ExceedingData(len(tail))
1589 def hexdecode(self, data, *args, **kwargs):
1590 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1592 return self.decode(hexdec(data), *args, **kwargs)
1594 def hexdecod(self, data, *args, **kwargs):
1595 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1597 return self.decod(hexdec(data), *args, **kwargs)
1601 """See :ref:`decoding`
1603 return self._expl is not None
1607 """See :ref:`decoding`
1612 def expl_tlen(self):
1613 """See :ref:`decoding`
1615 return len(self._expl)
1618 def expl_llen(self):
1619 """See :ref:`decoding`
1621 if self.expl_lenindef:
1623 return len(len_encode(self.tlvlen))
1626 def expl_offset(self):
1627 """See :ref:`decoding`
1629 return self.offset - self.expl_tlen - self.expl_llen
1632 def expl_vlen(self):
1633 """See :ref:`decoding`
1638 def expl_tlvlen(self):
1639 """See :ref:`decoding`
1641 return self.expl_tlen + self.expl_llen + self.expl_vlen
1644 def fulloffset(self):
1645 """See :ref:`decoding`
1647 return self.expl_offset if self.expled else self.offset
1651 """See :ref:`decoding`
1653 return self.expl_tlvlen if self.expled else self.tlvlen
1655 def pps_lenindef(self, decode_path):
1656 if self.lenindef and not (
1657 getattr(self, "defined", None) is not None and
1658 self.defined[1].lenindef
1661 asn1_type_name="EOC",
1663 decode_path=decode_path,
1665 self.offset + self.tlvlen -
1666 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1674 if self.expl_lenindef:
1676 asn1_type_name="EOC",
1677 obj_name="EXPLICIT",
1678 decode_path=decode_path,
1679 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1688 def encode_cer(obj):
1689 """Encode to CER in memory
1692 obj.encode_cer(buf.write)
1693 return buf.getvalue()
1696 class DecodePathDefBy(object):
1697 """DEFINED BY representation inside decode path
1699 __slots__ = ("defined_by",)
1701 def __init__(self, defined_by):
1702 self.defined_by = defined_by
1704 def __ne__(self, their):
1705 return not(self == their)
1707 def __eq__(self, their):
1708 if not isinstance(their, self.__class__):
1710 return self.defined_by == their.defined_by
1713 return "DEFINED BY " + str(self.defined_by)
1716 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1719 ########################################################################
1721 ########################################################################
1723 PP = namedtuple("PP", (
1746 ), **NAMEDTUPLE_KWARGS)
1751 asn1_type_name="unknown",
1768 expl_lenindef=False,
1799 def _colourize(what, colour, with_colours, attrs=("bold",)):
1800 return colored(what, colour, attrs=attrs) if with_colours else what
1803 def colonize_hex(hexed):
1804 """Separate hexadecimal string with colons
1806 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1815 with_decode_path=False,
1816 decode_path_len_decrease=0,
1823 " " if pp.expl_offset is None else
1824 ("-%d" % (pp.offset - pp.expl_offset))
1826 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1828 col = _colourize(col, "red", with_colours, ())
1829 col += _colourize("B", "red", with_colours) if pp.bered else " "
1831 col = "[%d,%d,%4d]%s" % (
1835 LENINDEF_PP_CHAR if pp.lenindef else " "
1837 col = _colourize(col, "green", with_colours, ())
1839 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1840 if decode_path_len > 0:
1841 cols.append(" ." * decode_path_len)
1842 ent = pp.decode_path[-1]
1843 if isinstance(ent, DecodePathDefBy):
1844 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1845 value = str(ent.defined_by)
1848 len(oid_maps) > 0 and
1849 ent.defined_by.asn1_type_name ==
1850 ObjectIdentifier.asn1_type_name
1852 for oid_map in oid_maps:
1853 oid_name = oid_map.get(value)
1854 if oid_name is not None:
1855 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1857 if oid_name is None:
1858 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1860 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1861 if pp.expl is not None:
1862 klass, _, num = pp.expl
1863 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1864 cols.append(_colourize(col, "blue", with_colours))
1865 if pp.impl is not None:
1866 klass, _, num = pp.impl
1867 col = "[%s%d]" % (TagClassReprs[klass], num)
1868 cols.append(_colourize(col, "blue", with_colours))
1869 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1870 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1872 cols.append(_colourize("BER", "red", with_colours))
1873 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1874 if pp.value is not None:
1876 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1878 len(oid_maps) > 0 and
1879 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1881 for oid_map in oid_maps:
1882 oid_name = oid_map.get(value)
1883 if oid_name is not None:
1884 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1886 if pp.asn1_type_name == Integer.asn1_type_name:
1887 hex_repr = hex(int(pp.obj._value))[2:].upper()
1888 if len(hex_repr) % 2 != 0:
1889 hex_repr = "0" + hex_repr
1890 cols.append(_colourize(
1891 "(%s)" % colonize_hex(hex_repr),
1896 if pp.blob.__class__ == binary_type:
1897 cols.append(hexenc(pp.blob))
1898 elif pp.blob.__class__ == tuple:
1899 cols.append(", ".join(pp.blob))
1901 cols.append(_colourize("OPTIONAL", "red", with_colours))
1903 cols.append(_colourize("DEFAULT", "red", with_colours))
1904 if with_decode_path:
1905 cols.append(_colourize(
1906 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1910 return " ".join(cols)
1913 def pp_console_blob(pp, decode_path_len_decrease=0):
1914 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1915 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1916 if decode_path_len > 0:
1917 cols.append(" ." * (decode_path_len + 1))
1918 if pp.blob.__class__ == binary_type:
1919 blob = hexenc(pp.blob).upper()
1920 for i in six_xrange(0, len(blob), 32):
1921 chunk = blob[i:i + 32]
1922 yield " ".join(cols + [colonize_hex(chunk)])
1923 elif pp.blob.__class__ == tuple:
1924 yield " ".join(cols + [", ".join(pp.blob)])
1932 with_decode_path=False,
1933 decode_path_only=(),
1935 """Pretty print object
1937 :param Obj obj: object you want to pretty print
1938 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1939 Its human readable form is printed when OID is met
1940 :param big_blobs: if large binary objects are met (like OctetString
1941 values), do we need to print them too, on separate
1943 :param with_colours: colourize output, if ``termcolor`` library
1945 :param with_decode_path: print decode path
1946 :param decode_path_only: print only that specified decode path
1948 def _pprint_pps(pps):
1950 if hasattr(pp, "_fields"):
1952 decode_path_only != () and
1954 str(p) for p in pp.decode_path[:len(decode_path_only)]
1955 ) != decode_path_only
1959 yield pp_console_row(
1964 with_colours=with_colours,
1965 with_decode_path=with_decode_path,
1966 decode_path_len_decrease=len(decode_path_only),
1968 for row in pp_console_blob(
1970 decode_path_len_decrease=len(decode_path_only),
1974 yield pp_console_row(
1979 with_colours=with_colours,
1980 with_decode_path=with_decode_path,
1981 decode_path_len_decrease=len(decode_path_only),
1984 for row in _pprint_pps(pp):
1986 return "\n".join(_pprint_pps(obj.pps()))
1989 ########################################################################
1990 # ASN.1 primitive types
1991 ########################################################################
1993 BooleanState = namedtuple(
1995 BasicState._fields + ("value",),
2001 """``BOOLEAN`` boolean type
2003 >>> b = Boolean(True)
2005 >>> b == Boolean(True)
2011 tag_default = tag_encode(1)
2012 asn1_type_name = "BOOLEAN"
2024 :param value: set the value. Either boolean type, or
2025 :py:class:`pyderasn.Boolean` object
2026 :param bytes impl: override default tag with ``IMPLICIT`` one
2027 :param bytes expl: override default tag with ``EXPLICIT`` one
2028 :param default: set default value. Type same as in ``value``
2029 :param bool optional: is object ``OPTIONAL`` in sequence
2031 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
2032 self._value = None if value is None else self._value_sanitize(value)
2033 if default is not None:
2034 default = self._value_sanitize(default)
2035 self.default = self.__class__(
2041 self._value = default
2043 def _value_sanitize(self, value):
2044 if value.__class__ == bool:
2046 if issubclass(value.__class__, Boolean):
2048 raise InvalidValueType((self.__class__, bool))
2052 return self._value is not None
2054 def __getstate__(self):
2055 return BooleanState(
2071 def __setstate__(self, state):
2072 super(Boolean, self).__setstate__(state)
2073 self._value = state.value
2075 def __nonzero__(self):
2076 self._assert_ready()
2080 self._assert_ready()
2083 def __eq__(self, their):
2084 if their.__class__ == bool:
2085 return self._value == their
2086 if not issubclass(their.__class__, Boolean):
2089 self._value == their._value and
2090 self.tag == their.tag and
2091 self._expl == their._expl
2102 return self.__class__(
2104 impl=self.tag if impl is None else impl,
2105 expl=self._expl if expl is None else expl,
2106 default=self.default if default is None else default,
2107 optional=self.optional if optional is None else optional,
2111 self._assert_ready()
2115 (b"\xFF" if self._value else b"\x00"),
2118 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2120 t, _, lv = tag_strip(tlv)
2121 except DecodeError as err:
2122 raise err.__class__(
2124 klass=self.__class__,
2125 decode_path=decode_path,
2130 klass=self.__class__,
2131 decode_path=decode_path,
2138 l, _, v = len_decode(lv)
2139 except DecodeError as err:
2140 raise err.__class__(
2142 klass=self.__class__,
2143 decode_path=decode_path,
2147 raise InvalidLength(
2148 "Boolean's length must be equal to 1",
2149 klass=self.__class__,
2150 decode_path=decode_path,
2154 raise NotEnoughData(
2155 "encoded length is longer than data",
2156 klass=self.__class__,
2157 decode_path=decode_path,
2160 first_octet = byte2int(v)
2162 if first_octet == 0:
2164 elif first_octet == 0xFF:
2166 elif ctx.get("bered", False):
2171 "unacceptable Boolean value",
2172 klass=self.__class__,
2173 decode_path=decode_path,
2176 obj = self.__class__(
2180 default=self.default,
2181 optional=self.optional,
2182 _decoded=(offset, 1, 1),
2184 obj.ber_encoded = ber_encoded
2185 yield decode_path, obj, v[1:]
2188 return pp_console_row(next(self.pps()))
2190 def pps(self, decode_path=()):
2193 asn1_type_name=self.asn1_type_name,
2194 obj_name=self.__class__.__name__,
2195 decode_path=decode_path,
2196 value=str(self._value) if self.ready else None,
2197 optional=self.optional,
2198 default=self == self.default,
2199 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2200 expl=None if self._expl is None else tag_decode(self._expl),
2205 expl_offset=self.expl_offset if self.expled else None,
2206 expl_tlen=self.expl_tlen if self.expled else None,
2207 expl_llen=self.expl_llen if self.expled else None,
2208 expl_vlen=self.expl_vlen if self.expled else None,
2209 expl_lenindef=self.expl_lenindef,
2210 ber_encoded=self.ber_encoded,
2213 for pp in self.pps_lenindef(decode_path):
2217 IntegerState = namedtuple(
2219 BasicState._fields + ("specs", "value", "bound_min", "bound_max"),
2225 """``INTEGER`` integer type
2227 >>> b = Integer(-123)
2229 >>> b == Integer(-123)
2234 >>> Integer(2, bounds=(1, 3))
2236 >>> Integer(5, bounds=(1, 3))
2237 Traceback (most recent call last):
2238 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2242 class Version(Integer):
2249 >>> v = Version("v1")
2256 {'v3': 2, 'v1': 0, 'v2': 1}
2258 __slots__ = ("specs", "_bound_min", "_bound_max")
2259 tag_default = tag_encode(2)
2260 asn1_type_name = "INTEGER"
2274 :param value: set the value. Either integer type, named value
2275 (if ``schema`` is specified in the class), or
2276 :py:class:`pyderasn.Integer` object
2277 :param bounds: set ``(MIN, MAX)`` value constraint.
2278 (-inf, +inf) by default
2279 :param bytes impl: override default tag with ``IMPLICIT`` one
2280 :param bytes expl: override default tag with ``EXPLICIT`` one
2281 :param default: set default value. Type same as in ``value``
2282 :param bool optional: is object ``OPTIONAL`` in sequence
2284 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2286 specs = getattr(self, "schema", {}) if _specs is None else _specs
2287 self.specs = specs if specs.__class__ == dict else dict(specs)
2288 self._bound_min, self._bound_max = getattr(
2291 (float("-inf"), float("+inf")),
2292 ) if bounds is None else bounds
2293 if value is not None:
2294 self._value = self._value_sanitize(value)
2295 if default is not None:
2296 default = self._value_sanitize(default)
2297 self.default = self.__class__(
2303 if self._value is None:
2304 self._value = default
2306 def _value_sanitize(self, value):
2307 if isinstance(value, integer_types):
2309 elif issubclass(value.__class__, Integer):
2310 value = value._value
2311 elif value.__class__ == str:
2312 value = self.specs.get(value)
2314 raise ObjUnknown("integer value: %s" % value)
2316 raise InvalidValueType((self.__class__, int, str))
2317 if not self._bound_min <= value <= self._bound_max:
2318 raise BoundsError(self._bound_min, value, self._bound_max)
2323 return self._value is not None
2325 def __getstate__(self):
2326 return IntegerState(
2345 def __setstate__(self, state):
2346 super(Integer, self).__setstate__(state)
2347 self.specs = state.specs
2348 self._value = state.value
2349 self._bound_min = state.bound_min
2350 self._bound_max = state.bound_max
2353 self._assert_ready()
2354 return int(self._value)
2357 self._assert_ready()
2360 bytes(self._expl or b"") +
2361 str(self._value).encode("ascii"),
2364 def __eq__(self, their):
2365 if isinstance(their, integer_types):
2366 return self._value == their
2367 if not issubclass(their.__class__, Integer):
2370 self._value == their._value and
2371 self.tag == their.tag and
2372 self._expl == their._expl
2375 def __lt__(self, their):
2376 return self._value < their._value
2380 """Return named representation (if exists) of the value
2382 for name, value in iteritems(self.specs):
2383 if value == self._value:
2396 return self.__class__(
2399 (self._bound_min, self._bound_max)
2400 if bounds is None else bounds
2402 impl=self.tag if impl is None else impl,
2403 expl=self._expl if expl is None else expl,
2404 default=self.default if default is None else default,
2405 optional=self.optional if optional is None else optional,
2410 self._assert_ready()
2414 octets = bytearray([0])
2418 octets = bytearray()
2420 octets.append((value & 0xFF) ^ 0xFF)
2422 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2425 octets = bytearray()
2427 octets.append(value & 0xFF)
2429 if octets[-1] & 0x80 > 0:
2432 octets = bytes(octets)
2434 bytes_len = ceil(value.bit_length() / 8) or 1
2437 octets = value.to_bytes(
2442 except OverflowError:
2446 return b"".join((self.tag, len_encode(len(octets)), octets))
2448 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2450 t, _, lv = tag_strip(tlv)
2451 except DecodeError as err:
2452 raise err.__class__(
2454 klass=self.__class__,
2455 decode_path=decode_path,
2460 klass=self.__class__,
2461 decode_path=decode_path,
2468 l, llen, v = len_decode(lv)
2469 except DecodeError as err:
2470 raise err.__class__(
2472 klass=self.__class__,
2473 decode_path=decode_path,
2477 raise NotEnoughData(
2478 "encoded length is longer than data",
2479 klass=self.__class__,
2480 decode_path=decode_path,
2484 raise NotEnoughData(
2486 klass=self.__class__,
2487 decode_path=decode_path,
2490 v, tail = v[:l], v[l:]
2491 first_octet = byte2int(v)
2493 second_octet = byte2int(v[1:])
2495 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2496 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2499 "non normalized integer",
2500 klass=self.__class__,
2501 decode_path=decode_path,
2506 if first_octet & 0x80 > 0:
2507 octets = bytearray()
2508 for octet in bytearray(v):
2509 octets.append(octet ^ 0xFF)
2510 for octet in octets:
2511 value = (value << 8) | octet
2515 for octet in bytearray(v):
2516 value = (value << 8) | octet
2518 value = int.from_bytes(v, byteorder="big", signed=True)
2520 obj = self.__class__(
2522 bounds=(self._bound_min, self._bound_max),
2525 default=self.default,
2526 optional=self.optional,
2528 _decoded=(offset, llen, l),
2530 except BoundsError as err:
2533 klass=self.__class__,
2534 decode_path=decode_path,
2537 yield decode_path, obj, tail
2540 return pp_console_row(next(self.pps()))
2542 def pps(self, decode_path=()):
2545 asn1_type_name=self.asn1_type_name,
2546 obj_name=self.__class__.__name__,
2547 decode_path=decode_path,
2548 value=(self.named or str(self._value)) if self.ready else None,
2549 optional=self.optional,
2550 default=self == self.default,
2551 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2552 expl=None if self._expl is None else tag_decode(self._expl),
2557 expl_offset=self.expl_offset if self.expled else None,
2558 expl_tlen=self.expl_tlen if self.expled else None,
2559 expl_llen=self.expl_llen if self.expled else None,
2560 expl_vlen=self.expl_vlen if self.expled else None,
2561 expl_lenindef=self.expl_lenindef,
2564 for pp in self.pps_lenindef(decode_path):
2568 BitStringState = namedtuple(
2570 BasicState._fields + ("specs", "value", "tag_constructed", "defined"),
2575 class BitString(Obj):
2576 """``BIT STRING`` bit string type
2578 >>> BitString(b"hello world")
2579 BIT STRING 88 bits 68656c6c6f20776f726c64
2582 >>> b == b"hello world"
2587 >>> BitString("'0A3B5F291CD'H")
2588 BIT STRING 44 bits 0a3b5f291cd0
2589 >>> b = BitString("'010110000000'B")
2590 BIT STRING 12 bits 5800
2593 >>> b[0], b[1], b[2], b[3]
2594 (False, True, False, True)
2598 [False, True, False, True, True, False, False, False, False, False, False, False]
2602 class KeyUsage(BitString):
2604 ("digitalSignature", 0),
2605 ("nonRepudiation", 1),
2606 ("keyEncipherment", 2),
2609 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2610 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2612 ['nonRepudiation', 'keyEncipherment']
2614 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2618 Pay attention that BIT STRING can be encoded both in primitive
2619 and constructed forms. Decoder always checks constructed form tag
2620 additionally to specified primitive one. If BER decoding is
2621 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2622 of DER restrictions.
2624 __slots__ = ("tag_constructed", "specs", "defined")
2625 tag_default = tag_encode(3)
2626 asn1_type_name = "BIT STRING"
2639 :param value: set the value. Either binary type, tuple of named
2640 values (if ``schema`` is specified in the class),
2641 string in ``'XXX...'B`` form, or
2642 :py:class:`pyderasn.BitString` object
2643 :param bytes impl: override default tag with ``IMPLICIT`` one
2644 :param bytes expl: override default tag with ``EXPLICIT`` one
2645 :param default: set default value. Type same as in ``value``
2646 :param bool optional: is object ``OPTIONAL`` in sequence
2648 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2649 specs = getattr(self, "schema", {}) if _specs is None else _specs
2650 self.specs = specs if specs.__class__ == dict else dict(specs)
2651 self._value = None if value is None else self._value_sanitize(value)
2652 if default is not None:
2653 default = self._value_sanitize(default)
2654 self.default = self.__class__(
2660 self._value = default
2662 tag_klass, _, tag_num = tag_decode(self.tag)
2663 self.tag_constructed = tag_encode(
2665 form=TagFormConstructed,
2669 def _bits2octets(self, bits):
2670 if len(self.specs) > 0:
2671 bits = bits.rstrip("0")
2673 bits += "0" * ((8 - (bit_len % 8)) % 8)
2674 octets = bytearray(len(bits) // 8)
2675 for i in six_xrange(len(octets)):
2676 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2677 return bit_len, bytes(octets)
2679 def _value_sanitize(self, value):
2680 if isinstance(value, (string_types, binary_type)):
2682 isinstance(value, string_types) and
2683 value.startswith("'")
2685 if value.endswith("'B"):
2687 if not frozenset(value) <= SET01:
2688 raise ValueError("B's coding contains unacceptable chars")
2689 return self._bits2octets(value)
2690 if value.endswith("'H"):
2694 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2696 if value.__class__ == binary_type:
2697 return (len(value) * 8, value)
2698 raise InvalidValueType((self.__class__, string_types, binary_type))
2699 if value.__class__ == tuple:
2702 isinstance(value[0], integer_types) and
2703 value[1].__class__ == binary_type
2708 bit = self.specs.get(name)
2710 raise ObjUnknown("BitString value: %s" % name)
2713 return self._bits2octets("")
2714 bits = frozenset(bits)
2715 return self._bits2octets("".join(
2716 ("1" if bit in bits else "0")
2717 for bit in six_xrange(max(bits) + 1)
2719 if issubclass(value.__class__, BitString):
2721 raise InvalidValueType((self.__class__, binary_type, string_types))
2725 return self._value is not None
2727 def __getstate__(self):
2728 return BitStringState(
2743 self.tag_constructed,
2747 def __setstate__(self, state):
2748 super(BitString, self).__setstate__(state)
2749 self.specs = state.specs
2750 self._value = state.value
2751 self.tag_constructed = state.tag_constructed
2752 self.defined = state.defined
2755 self._assert_ready()
2756 for i in six_xrange(self._value[0]):
2761 """Returns number of bits in the string
2763 self._assert_ready()
2764 return self._value[0]
2766 def __bytes__(self):
2767 self._assert_ready()
2768 return self._value[1]
2770 def __eq__(self, their):
2771 if their.__class__ == bytes:
2772 return self._value[1] == their
2773 if not issubclass(their.__class__, BitString):
2776 self._value == their._value and
2777 self.tag == their.tag and
2778 self._expl == their._expl
2783 """Named representation (if exists) of the bits
2785 :returns: [str(name), ...]
2787 return [name for name, bit in iteritems(self.specs) if self[bit]]
2797 return self.__class__(
2799 impl=self.tag if impl is None else impl,
2800 expl=self._expl if expl is None else expl,
2801 default=self.default if default is None else default,
2802 optional=self.optional if optional is None else optional,
2806 def __getitem__(self, key):
2807 if key.__class__ == int:
2808 bit_len, octets = self._value
2812 byte2int(memoryview(octets)[key // 8:]) >>
2815 if isinstance(key, string_types):
2816 value = self.specs.get(key)
2818 raise ObjUnknown("BitString value: %s" % key)
2820 raise InvalidValueType((int, str))
2823 self._assert_ready()
2824 bit_len, octets = self._value
2827 len_encode(len(octets) + 1),
2828 int2byte((8 - bit_len % 8) % 8),
2832 def _encode_cer(self, writer):
2833 bit_len, octets = self._value
2834 if len(octets) + 1 <= 1000:
2835 write_full(writer, self._encode())
2837 write_full(writer, self.tag_constructed)
2838 write_full(writer, LENINDEF)
2839 for offset in six_xrange(0, (len(octets) // 999) * 999, 999):
2840 write_full(writer, b"".join((
2841 BitString.tag_default,
2844 octets[offset:offset + 999],
2846 tail = octets[offset+999:]
2848 tail = int2byte((8 - bit_len % 8) % 8) + tail
2849 write_full(writer, b"".join((
2850 BitString.tag_default,
2851 len_encode(len(tail)),
2854 write_full(writer, EOC)
2856 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2858 t, tlen, lv = tag_strip(tlv)
2859 except DecodeError as err:
2860 raise err.__class__(
2862 klass=self.__class__,
2863 decode_path=decode_path,
2867 if tag_only: # pragma: no cover
2871 l, llen, v = len_decode(lv)
2872 except DecodeError as err:
2873 raise err.__class__(
2875 klass=self.__class__,
2876 decode_path=decode_path,
2880 raise NotEnoughData(
2881 "encoded length is longer than data",
2882 klass=self.__class__,
2883 decode_path=decode_path,
2887 raise NotEnoughData(
2889 klass=self.__class__,
2890 decode_path=decode_path,
2893 pad_size = byte2int(v)
2894 if l == 1 and pad_size != 0:
2896 "invalid empty value",
2897 klass=self.__class__,
2898 decode_path=decode_path,
2904 klass=self.__class__,
2905 decode_path=decode_path,
2908 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2911 klass=self.__class__,
2912 decode_path=decode_path,
2915 v, tail = v[:l], v[l:]
2916 bit_len = (len(v) - 1) * 8 - pad_size
2917 obj = self.__class__(
2918 value=None if evgen_mode else (bit_len, v[1:].tobytes()),
2921 default=self.default,
2922 optional=self.optional,
2924 _decoded=(offset, llen, l),
2927 obj._value = (bit_len, None)
2928 yield decode_path, obj, tail
2930 if t != self.tag_constructed:
2932 klass=self.__class__,
2933 decode_path=decode_path,
2936 if not ctx.get("bered", False):
2938 "unallowed BER constructed encoding",
2939 klass=self.__class__,
2940 decode_path=decode_path,
2943 if tag_only: # pragma: no cover
2948 l, llen, v = len_decode(lv)
2949 except LenIndefForm:
2950 llen, l, v = 1, 0, lv[1:]
2952 except DecodeError as err:
2953 raise err.__class__(
2955 klass=self.__class__,
2956 decode_path=decode_path,
2960 raise NotEnoughData(
2961 "encoded length is longer than data",
2962 klass=self.__class__,
2963 decode_path=decode_path,
2966 if not lenindef and l == 0:
2967 raise NotEnoughData(
2969 klass=self.__class__,
2970 decode_path=decode_path,
2974 sub_offset = offset + tlen + llen
2978 if v[:EOC_LEN].tobytes() == EOC:
2985 "chunk out of bounds",
2986 klass=self.__class__,
2987 decode_path=decode_path + (str(len(chunks) - 1),),
2988 offset=chunks[-1].offset,
2990 sub_decode_path = decode_path + (str(len(chunks)),)
2993 for _decode_path, chunk, v_tail in BitString().decode_evgen(
2996 decode_path=sub_decode_path,
2999 _ctx_immutable=False,
3001 yield _decode_path, chunk, v_tail
3003 _, chunk, v_tail = next(BitString().decode_evgen(
3006 decode_path=sub_decode_path,
3009 _ctx_immutable=False,
3014 "expected BitString encoded chunk",
3015 klass=self.__class__,
3016 decode_path=sub_decode_path,
3019 chunks.append(chunk)
3020 sub_offset += chunk.tlvlen
3021 vlen += chunk.tlvlen
3023 if len(chunks) == 0:
3026 klass=self.__class__,
3027 decode_path=decode_path,
3032 for chunk_i, chunk in enumerate(chunks[:-1]):
3033 if chunk.bit_len % 8 != 0:
3035 "BitString chunk is not multiple of 8 bits",
3036 klass=self.__class__,
3037 decode_path=decode_path + (str(chunk_i),),
3038 offset=chunk.offset,
3041 values.append(bytes(chunk))
3042 bit_len += chunk.bit_len
3043 chunk_last = chunks[-1]
3045 values.append(bytes(chunk_last))
3046 bit_len += chunk_last.bit_len
3047 obj = self.__class__(
3048 value=None if evgen_mode else (bit_len, b"".join(values)),
3051 default=self.default,
3052 optional=self.optional,
3054 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3057 obj._value = (bit_len, None)
3058 obj.lenindef = lenindef
3059 obj.ber_encoded = True
3060 yield decode_path, obj, (v[EOC_LEN:] if lenindef else v)
3063 return pp_console_row(next(self.pps()))
3065 def pps(self, decode_path=()):
3069 bit_len, blob = self._value
3070 value = "%d bits" % bit_len
3071 if len(self.specs) > 0 and blob is not None:
3072 blob = tuple(self.named)
3075 asn1_type_name=self.asn1_type_name,
3076 obj_name=self.__class__.__name__,
3077 decode_path=decode_path,
3080 optional=self.optional,
3081 default=self == self.default,
3082 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3083 expl=None if self._expl is None else tag_decode(self._expl),
3088 expl_offset=self.expl_offset if self.expled else None,
3089 expl_tlen=self.expl_tlen if self.expled else None,
3090 expl_llen=self.expl_llen if self.expled else None,
3091 expl_vlen=self.expl_vlen if self.expled else None,
3092 expl_lenindef=self.expl_lenindef,
3093 lenindef=self.lenindef,
3094 ber_encoded=self.ber_encoded,
3097 defined_by, defined = self.defined or (None, None)
3098 if defined_by is not None:
3100 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3102 for pp in self.pps_lenindef(decode_path):
3106 OctetStringState = namedtuple(
3108 BasicState._fields + (
3119 class OctetString(Obj):
3120 """``OCTET STRING`` binary string type
3122 >>> s = OctetString(b"hello world")
3123 OCTET STRING 11 bytes 68656c6c6f20776f726c64
3124 >>> s == OctetString(b"hello world")
3129 >>> OctetString(b"hello", bounds=(4, 4))
3130 Traceback (most recent call last):
3131 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
3132 >>> OctetString(b"hell", bounds=(4, 4))
3133 OCTET STRING 4 bytes 68656c6c
3137 Pay attention that OCTET STRING can be encoded both in primitive
3138 and constructed forms. Decoder always checks constructed form tag
3139 additionally to specified primitive one. If BER decoding is
3140 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
3141 of DER restrictions.
3143 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
3144 tag_default = tag_encode(4)
3145 asn1_type_name = "OCTET STRING"
3146 evgen_mode_skip_value = True
3160 :param value: set the value. Either binary type, or
3161 :py:class:`pyderasn.OctetString` object
3162 :param bounds: set ``(MIN, MAX)`` value size constraint.
3163 (-inf, +inf) by default
3164 :param bytes impl: override default tag with ``IMPLICIT`` one
3165 :param bytes expl: override default tag with ``EXPLICIT`` one
3166 :param default: set default value. Type same as in ``value``
3167 :param bool optional: is object ``OPTIONAL`` in sequence
3169 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
3171 self._bound_min, self._bound_max = getattr(
3175 ) if bounds is None else bounds
3176 if value is not None:
3177 self._value = self._value_sanitize(value)
3178 if default is not None:
3179 default = self._value_sanitize(default)
3180 self.default = self.__class__(
3185 if self._value is None:
3186 self._value = default
3188 tag_klass, _, tag_num = tag_decode(self.tag)
3189 self.tag_constructed = tag_encode(
3191 form=TagFormConstructed,
3195 def _value_sanitize(self, value):
3196 if value.__class__ == binary_type:
3198 elif issubclass(value.__class__, OctetString):
3199 value = value._value
3201 raise InvalidValueType((self.__class__, bytes))
3202 if not self._bound_min <= len(value) <= self._bound_max:
3203 raise BoundsError(self._bound_min, len(value), self._bound_max)
3208 return self._value is not None
3210 def __getstate__(self):
3211 return OctetStringState(
3227 self.tag_constructed,
3231 def __setstate__(self, state):
3232 super(OctetString, self).__setstate__(state)
3233 self._value = state.value
3234 self._bound_min = state.bound_min
3235 self._bound_max = state.bound_max
3236 self.tag_constructed = state.tag_constructed
3237 self.defined = state.defined
3239 def __bytes__(self):
3240 self._assert_ready()
3243 def __eq__(self, their):
3244 if their.__class__ == binary_type:
3245 return self._value == their
3246 if not issubclass(their.__class__, OctetString):
3249 self._value == their._value and
3250 self.tag == their.tag and
3251 self._expl == their._expl
3254 def __lt__(self, their):
3255 return self._value < their._value
3266 return self.__class__(
3269 (self._bound_min, self._bound_max)
3270 if bounds is None else bounds
3272 impl=self.tag if impl is None else impl,
3273 expl=self._expl if expl is None else expl,
3274 default=self.default if default is None else default,
3275 optional=self.optional if optional is None else optional,
3279 self._assert_ready()
3282 len_encode(len(self._value)),
3286 def _encode_cer(self, writer):
3287 octets = self._value
3288 if len(octets) <= 1000:
3289 write_full(writer, self._encode())
3291 write_full(writer, self.tag_constructed)
3292 write_full(writer, LENINDEF)
3293 for offset in six_xrange(0, (len(octets) // 1000) * 1000, 1000):
3294 write_full(writer, b"".join((
3295 OctetString.tag_default,
3297 octets[offset:offset + 1000],
3299 tail = octets[offset+1000:]
3301 write_full(writer, b"".join((
3302 OctetString.tag_default,
3303 len_encode(len(tail)),
3306 write_full(writer, EOC)
3308 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3310 t, tlen, lv = tag_strip(tlv)
3311 except DecodeError as err:
3312 raise err.__class__(
3314 klass=self.__class__,
3315 decode_path=decode_path,
3323 l, llen, v = len_decode(lv)
3324 except DecodeError as err:
3325 raise err.__class__(
3327 klass=self.__class__,
3328 decode_path=decode_path,
3332 raise NotEnoughData(
3333 "encoded length is longer than data",
3334 klass=self.__class__,
3335 decode_path=decode_path,
3338 v, tail = v[:l], v[l:]
3339 if evgen_mode and not self._bound_min <= len(v) <= self._bound_max:
3341 msg=str(BoundsError(self._bound_min, len(v), self._bound_max)),
3342 klass=self.__class__,
3343 decode_path=decode_path,
3347 obj = self.__class__(
3349 None if (evgen_mode and self.evgen_mode_skip_value)
3352 bounds=(self._bound_min, self._bound_max),
3355 default=self.default,
3356 optional=self.optional,
3357 _decoded=(offset, llen, l),
3360 except DecodeError as err:
3363 klass=self.__class__,
3364 decode_path=decode_path,
3367 except BoundsError as err:
3370 klass=self.__class__,
3371 decode_path=decode_path,
3374 yield decode_path, obj, tail
3376 if t != self.tag_constructed:
3378 klass=self.__class__,
3379 decode_path=decode_path,
3382 if not ctx.get("bered", False):
3384 "unallowed BER constructed encoding",
3385 klass=self.__class__,
3386 decode_path=decode_path,
3394 l, llen, v = len_decode(lv)
3395 except LenIndefForm:
3396 llen, l, v = 1, 0, lv[1:]
3398 except DecodeError as err:
3399 raise err.__class__(
3401 klass=self.__class__,
3402 decode_path=decode_path,
3406 raise NotEnoughData(
3407 "encoded length is longer than data",
3408 klass=self.__class__,
3409 decode_path=decode_path,
3414 sub_offset = offset + tlen + llen
3419 if v[:EOC_LEN].tobytes() == EOC:
3426 "chunk out of bounds",
3427 klass=self.__class__,
3428 decode_path=decode_path + (str(len(chunks) - 1),),
3429 offset=chunks[-1].offset,
3433 sub_decode_path = decode_path + (str(chunks_count),)
3434 for _decode_path, chunk, v_tail in OctetString().decode_evgen(
3437 decode_path=sub_decode_path,
3440 _ctx_immutable=False,
3442 yield _decode_path, chunk, v_tail
3443 if not chunk.ber_encoded:
3444 payload_len += chunk.vlen
3447 sub_decode_path = decode_path + (str(len(chunks)),)
3448 _, chunk, v_tail = next(OctetString().decode_evgen(
3451 decode_path=sub_decode_path,
3454 _ctx_immutable=False,
3457 chunks.append(chunk)
3460 "expected OctetString encoded chunk",
3461 klass=self.__class__,
3462 decode_path=sub_decode_path,
3465 sub_offset += chunk.tlvlen
3466 vlen += chunk.tlvlen
3468 if evgen_mode and not self._bound_min <= payload_len <= self._bound_max:
3470 msg=str(BoundsError(self._bound_min, payload_len, self._bound_max)),
3471 klass=self.__class__,
3472 decode_path=decode_path,
3476 obj = self.__class__(
3478 None if evgen_mode else
3479 b"".join(bytes(chunk) for chunk in chunks)
3481 bounds=(self._bound_min, self._bound_max),
3484 default=self.default,
3485 optional=self.optional,
3486 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3489 except DecodeError as err:
3492 klass=self.__class__,
3493 decode_path=decode_path,
3496 except BoundsError as err:
3499 klass=self.__class__,
3500 decode_path=decode_path,
3503 obj.lenindef = lenindef
3504 obj.ber_encoded = True
3505 yield decode_path, obj, (v[EOC_LEN:] if lenindef else v)
3508 return pp_console_row(next(self.pps()))
3510 def pps(self, decode_path=()):
3513 asn1_type_name=self.asn1_type_name,
3514 obj_name=self.__class__.__name__,
3515 decode_path=decode_path,
3516 value=("%d bytes" % len(self._value)) if self.ready else None,
3517 blob=self._value if self.ready else None,
3518 optional=self.optional,
3519 default=self == self.default,
3520 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3521 expl=None if self._expl is None else tag_decode(self._expl),
3526 expl_offset=self.expl_offset if self.expled else None,
3527 expl_tlen=self.expl_tlen if self.expled else None,
3528 expl_llen=self.expl_llen if self.expled else None,
3529 expl_vlen=self.expl_vlen if self.expled else None,
3530 expl_lenindef=self.expl_lenindef,
3531 lenindef=self.lenindef,
3532 ber_encoded=self.ber_encoded,
3535 defined_by, defined = self.defined or (None, None)
3536 if defined_by is not None:
3538 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3540 for pp in self.pps_lenindef(decode_path):
3544 NullState = namedtuple("NullState", BasicState._fields, **NAMEDTUPLE_KWARGS)
3548 """``NULL`` null object
3556 tag_default = tag_encode(5)
3557 asn1_type_name = "NULL"
3561 value=None, # unused, but Sequence passes it
3568 :param bytes impl: override default tag with ``IMPLICIT`` one
3569 :param bytes expl: override default tag with ``EXPLICIT`` one
3570 :param bool optional: is object ``OPTIONAL`` in sequence
3572 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3579 def __getstate__(self):
3595 def __eq__(self, their):
3596 if not issubclass(their.__class__, Null):
3599 self.tag == their.tag and
3600 self._expl == their._expl
3610 return self.__class__(
3611 impl=self.tag if impl is None else impl,
3612 expl=self._expl if expl is None else expl,
3613 optional=self.optional if optional is None else optional,
3617 return self.tag + len_encode(0)
3619 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3621 t, _, lv = tag_strip(tlv)
3622 except DecodeError as err:
3623 raise err.__class__(
3625 klass=self.__class__,
3626 decode_path=decode_path,
3631 klass=self.__class__,
3632 decode_path=decode_path,
3635 if tag_only: # pragma: no cover
3639 l, _, v = len_decode(lv)
3640 except DecodeError as err:
3641 raise err.__class__(
3643 klass=self.__class__,
3644 decode_path=decode_path,
3648 raise InvalidLength(
3649 "Null must have zero length",
3650 klass=self.__class__,
3651 decode_path=decode_path,
3654 obj = self.__class__(
3657 optional=self.optional,
3658 _decoded=(offset, 1, 0),
3660 yield decode_path, obj, v
3663 return pp_console_row(next(self.pps()))
3665 def pps(self, decode_path=()):
3668 asn1_type_name=self.asn1_type_name,
3669 obj_name=self.__class__.__name__,
3670 decode_path=decode_path,
3671 optional=self.optional,
3672 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3673 expl=None if self._expl is None else tag_decode(self._expl),
3678 expl_offset=self.expl_offset if self.expled else None,
3679 expl_tlen=self.expl_tlen if self.expled else None,
3680 expl_llen=self.expl_llen if self.expled else None,
3681 expl_vlen=self.expl_vlen if self.expled else None,
3682 expl_lenindef=self.expl_lenindef,
3685 for pp in self.pps_lenindef(decode_path):
3689 ObjectIdentifierState = namedtuple(
3690 "ObjectIdentifierState",
3691 BasicState._fields + ("value", "defines"),
3696 class ObjectIdentifier(Obj):
3697 """``OBJECT IDENTIFIER`` OID type
3699 >>> oid = ObjectIdentifier((1, 2, 3))
3700 OBJECT IDENTIFIER 1.2.3
3701 >>> oid == ObjectIdentifier("1.2.3")
3707 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3708 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3710 >>> str(ObjectIdentifier((3, 1)))
3711 Traceback (most recent call last):
3712 pyderasn.InvalidOID: unacceptable first arc value
3714 __slots__ = ("defines",)
3715 tag_default = tag_encode(6)
3716 asn1_type_name = "OBJECT IDENTIFIER"
3729 :param value: set the value. Either tuples of integers,
3730 string of "."-concatenated integers, or
3731 :py:class:`pyderasn.ObjectIdentifier` object
3732 :param defines: sequence of tuples. Each tuple has two elements.
3733 First one is relative to current one decode
3734 path, aiming to the field defined by that OID.
3735 Read about relative path in
3736 :py:func:`pyderasn.abs_decode_path`. Second
3737 tuple element is ``{OID: pyderasn.Obj()}``
3738 dictionary, mapping between current OID value
3739 and structure applied to defined field.
3740 :ref:`Read about DEFINED BY <definedby>`
3741 :param bytes impl: override default tag with ``IMPLICIT`` one
3742 :param bytes expl: override default tag with ``EXPLICIT`` one
3743 :param default: set default value. Type same as in ``value``
3744 :param bool optional: is object ``OPTIONAL`` in sequence
3746 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3748 if value is not None:
3749 self._value = self._value_sanitize(value)
3750 if default is not None:
3751 default = self._value_sanitize(default)
3752 self.default = self.__class__(
3757 if self._value is None:
3758 self._value = default
3759 self.defines = defines
3761 def __add__(self, their):
3762 if their.__class__ == tuple:
3763 return self.__class__(self._value + their)
3764 if isinstance(their, self.__class__):
3765 return self.__class__(self._value + their._value)
3766 raise InvalidValueType((self.__class__, tuple))
3768 def _value_sanitize(self, value):
3769 if issubclass(value.__class__, ObjectIdentifier):
3771 if isinstance(value, string_types):
3773 value = tuple(pureint(arc) for arc in value.split("."))
3775 raise InvalidOID("unacceptable arcs values")
3776 if value.__class__ == tuple:
3778 raise InvalidOID("less than 2 arcs")
3779 first_arc = value[0]
3780 if first_arc in (0, 1):
3781 if not (0 <= value[1] <= 39):
3782 raise InvalidOID("second arc is too wide")
3783 elif first_arc == 2:
3786 raise InvalidOID("unacceptable first arc value")
3787 if not all(arc >= 0 for arc in value):
3788 raise InvalidOID("negative arc value")
3790 raise InvalidValueType((self.__class__, str, tuple))
3794 return self._value is not None
3796 def __getstate__(self):
3797 return ObjectIdentifierState(
3814 def __setstate__(self, state):
3815 super(ObjectIdentifier, self).__setstate__(state)
3816 self._value = state.value
3817 self.defines = state.defines
3820 self._assert_ready()
3821 return iter(self._value)
3824 return ".".join(str(arc) for arc in self._value or ())
3827 self._assert_ready()
3830 bytes(self._expl or b"") +
3831 str(self._value).encode("ascii"),
3834 def __eq__(self, their):
3835 if their.__class__ == tuple:
3836 return self._value == their
3837 if not issubclass(their.__class__, ObjectIdentifier):
3840 self.tag == their.tag and
3841 self._expl == their._expl and
3842 self._value == their._value
3845 def __lt__(self, their):
3846 return self._value < their._value
3857 return self.__class__(
3859 defines=self.defines if defines is None else defines,
3860 impl=self.tag if impl is None else impl,
3861 expl=self._expl if expl is None else expl,
3862 default=self.default if default is None else default,
3863 optional=self.optional if optional is None else optional,
3867 self._assert_ready()
3869 first_value = value[1]
3870 first_arc = value[0]
3873 elif first_arc == 1:
3875 elif first_arc == 2:
3877 else: # pragma: no cover
3878 raise RuntimeError("invalid arc is stored")
3879 octets = [zero_ended_encode(first_value)]
3880 for arc in value[2:]:
3881 octets.append(zero_ended_encode(arc))
3882 v = b"".join(octets)
3883 return b"".join((self.tag, len_encode(len(v)), v))
3885 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3887 t, _, lv = tag_strip(tlv)
3888 except DecodeError as err:
3889 raise err.__class__(
3891 klass=self.__class__,
3892 decode_path=decode_path,
3897 klass=self.__class__,
3898 decode_path=decode_path,
3901 if tag_only: # pragma: no cover
3905 l, llen, v = len_decode(lv)
3906 except DecodeError as err:
3907 raise err.__class__(
3909 klass=self.__class__,
3910 decode_path=decode_path,
3914 raise NotEnoughData(
3915 "encoded length is longer than data",
3916 klass=self.__class__,
3917 decode_path=decode_path,
3921 raise NotEnoughData(
3923 klass=self.__class__,
3924 decode_path=decode_path,
3927 v, tail = v[:l], v[l:]
3934 octet = indexbytes(v, i)
3935 if i == 0 and octet == 0x80:
3936 if ctx.get("bered", False):
3939 raise DecodeError("non normalized arc encoding")
3940 arc = (arc << 7) | (octet & 0x7F)
3941 if octet & 0x80 == 0:
3949 klass=self.__class__,
3950 decode_path=decode_path,
3954 second_arc = arcs[0]
3955 if 0 <= second_arc <= 39:
3957 elif 40 <= second_arc <= 79:
3963 obj = self.__class__(
3964 value=tuple([first_arc, second_arc] + arcs[1:]),
3967 default=self.default,
3968 optional=self.optional,
3969 _decoded=(offset, llen, l),
3972 obj.ber_encoded = True
3973 yield decode_path, obj, tail
3976 return pp_console_row(next(self.pps()))
3978 def pps(self, decode_path=()):
3981 asn1_type_name=self.asn1_type_name,
3982 obj_name=self.__class__.__name__,
3983 decode_path=decode_path,
3984 value=str(self) if self.ready else None,
3985 optional=self.optional,
3986 default=self == self.default,
3987 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3988 expl=None if self._expl is None else tag_decode(self._expl),
3993 expl_offset=self.expl_offset if self.expled else None,
3994 expl_tlen=self.expl_tlen if self.expled else None,
3995 expl_llen=self.expl_llen if self.expled else None,
3996 expl_vlen=self.expl_vlen if self.expled else None,
3997 expl_lenindef=self.expl_lenindef,
3998 ber_encoded=self.ber_encoded,
4001 for pp in self.pps_lenindef(decode_path):
4005 class Enumerated(Integer):
4006 """``ENUMERATED`` integer type
4008 This type is identical to :py:class:`pyderasn.Integer`, but requires
4009 schema to be specified and does not accept values missing from it.
4012 tag_default = tag_encode(10)
4013 asn1_type_name = "ENUMERATED"
4024 bounds=None, # dummy argument, workability for Integer.decode
4026 super(Enumerated, self).__init__(
4027 value, bounds, impl, expl, default, optional, _specs, _decoded,
4029 if len(self.specs) == 0:
4030 raise ValueError("schema must be specified")
4032 def _value_sanitize(self, value):
4033 if isinstance(value, self.__class__):
4034 value = value._value
4035 elif isinstance(value, integer_types):
4036 for _value in itervalues(self.specs):
4041 "unknown integer value: %s" % value,
4042 klass=self.__class__,
4044 elif isinstance(value, string_types):
4045 value = self.specs.get(value)
4047 raise ObjUnknown("integer value: %s" % value)
4049 raise InvalidValueType((self.__class__, int, str))
4061 return self.__class__(
4063 impl=self.tag if impl is None else impl,
4064 expl=self._expl if expl is None else expl,
4065 default=self.default if default is None else default,
4066 optional=self.optional if optional is None else optional,
4071 def escape_control_unicode(c):
4072 if unicat(c)[0] == "C":
4073 c = repr(c).lstrip("u").strip("'")
4077 class CommonString(OctetString):
4078 """Common class for all strings
4080 Everything resembles :py:class:`pyderasn.OctetString`, except
4081 ability to deal with unicode text strings.
4083 >>> hexenc("привет мир".encode("utf-8"))
4084 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
4085 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
4087 >>> s = UTF8String("привет мир")
4088 UTF8String UTF8String привет мир
4090 'привет мир'
4091 >>> hexenc(bytes(s))
4092 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
4094 >>> PrintableString("привет мир")
4095 Traceback (most recent call last):
4096 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
4098 >>> BMPString("ада", bounds=(2, 2))
4099 Traceback (most recent call last):
4100 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
4101 >>> s = BMPString("ад", bounds=(2, 2))
4104 >>> hexenc(bytes(s))
4112 * - :py:class:`pyderasn.UTF8String`
4114 * - :py:class:`pyderasn.NumericString`
4116 * - :py:class:`pyderasn.PrintableString`
4118 * - :py:class:`pyderasn.TeletexString`
4120 * - :py:class:`pyderasn.T61String`
4122 * - :py:class:`pyderasn.VideotexString`
4124 * - :py:class:`pyderasn.IA5String`
4126 * - :py:class:`pyderasn.GraphicString`
4128 * - :py:class:`pyderasn.VisibleString`
4130 * - :py:class:`pyderasn.ISO646String`
4132 * - :py:class:`pyderasn.GeneralString`
4134 * - :py:class:`pyderasn.UniversalString`
4136 * - :py:class:`pyderasn.BMPString`
4141 def _value_sanitize(self, value):
4143 value_decoded = None
4144 if isinstance(value, self.__class__):
4145 value_raw = value._value
4146 elif value.__class__ == text_type:
4147 value_decoded = value
4148 elif value.__class__ == binary_type:
4151 raise InvalidValueType((self.__class__, text_type, binary_type))
4154 value_decoded.encode(self.encoding)
4155 if value_raw is None else value_raw
4158 value_raw.decode(self.encoding)
4159 if value_decoded is None else value_decoded
4161 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4162 raise DecodeError(str(err))
4163 if not self._bound_min <= len(value_decoded) <= self._bound_max:
4171 def __eq__(self, their):
4172 if their.__class__ == binary_type:
4173 return self._value == their
4174 if their.__class__ == text_type:
4175 return self._value == their.encode(self.encoding)
4176 if not isinstance(their, self.__class__):
4179 self._value == their._value and
4180 self.tag == their.tag and
4181 self._expl == their._expl
4184 def __unicode__(self):
4186 return self._value.decode(self.encoding)
4187 return text_type(self._value)
4190 return pp_console_row(next(self.pps(no_unicode=PY2)))
4192 def pps(self, decode_path=(), no_unicode=False):
4196 hexenc(bytes(self)) if no_unicode else
4197 "".join(escape_control_unicode(c) for c in self.__unicode__())
4201 asn1_type_name=self.asn1_type_name,
4202 obj_name=self.__class__.__name__,
4203 decode_path=decode_path,
4205 optional=self.optional,
4206 default=self == self.default,
4207 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4208 expl=None if self._expl is None else tag_decode(self._expl),
4213 expl_offset=self.expl_offset if self.expled else None,
4214 expl_tlen=self.expl_tlen if self.expled else None,
4215 expl_llen=self.expl_llen if self.expled else None,
4216 expl_vlen=self.expl_vlen if self.expled else None,
4217 expl_lenindef=self.expl_lenindef,
4218 ber_encoded=self.ber_encoded,
4221 for pp in self.pps_lenindef(decode_path):
4225 class UTF8String(CommonString):
4227 tag_default = tag_encode(12)
4229 asn1_type_name = "UTF8String"
4232 class AllowableCharsMixin(object):
4234 def allowable_chars(self):
4236 return self._allowable_chars
4237 return frozenset(six_unichr(c) for c in self._allowable_chars)
4240 class NumericString(AllowableCharsMixin, CommonString):
4243 Its value is properly sanitized: only ASCII digits with spaces can
4246 >>> NumericString().allowable_chars
4247 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
4250 tag_default = tag_encode(18)
4252 asn1_type_name = "NumericString"
4253 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
4255 def _value_sanitize(self, value):
4256 value = super(NumericString, self)._value_sanitize(value)
4257 if not frozenset(value) <= self._allowable_chars:
4258 raise DecodeError("non-numeric value")
4262 PrintableStringState = namedtuple(
4263 "PrintableStringState",
4264 OctetStringState._fields + ("allowable_chars",),
4269 class PrintableString(AllowableCharsMixin, CommonString):
4272 Its value is properly sanitized: see X.680 41.4 table 10.
4274 >>> PrintableString().allowable_chars
4275 frozenset([' ', "'", ..., 'z'])
4276 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4277 PrintableString PrintableString foo*bar
4278 >>> obj.allow_asterisk, obj.allow_ampersand
4282 tag_default = tag_encode(19)
4284 asn1_type_name = "PrintableString"
4285 _allowable_chars = frozenset(
4286 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4288 _asterisk = frozenset("*".encode("ascii"))
4289 _ampersand = frozenset("&".encode("ascii"))
4301 allow_asterisk=False,
4302 allow_ampersand=False,
4305 :param allow_asterisk: allow asterisk character
4306 :param allow_ampersand: allow ampersand character
4309 self._allowable_chars |= self._asterisk
4311 self._allowable_chars |= self._ampersand
4312 super(PrintableString, self).__init__(
4313 value, bounds, impl, expl, default, optional, _decoded, ctx,
4317 def allow_asterisk(self):
4318 """Is asterisk character allowed?
4320 return self._asterisk <= self._allowable_chars
4323 def allow_ampersand(self):
4324 """Is ampersand character allowed?
4326 return self._ampersand <= self._allowable_chars
4328 def _value_sanitize(self, value):
4329 value = super(PrintableString, self)._value_sanitize(value)
4330 if not frozenset(value) <= self._allowable_chars:
4331 raise DecodeError("non-printable value")
4334 def __getstate__(self):
4335 return PrintableStringState(
4336 *super(PrintableString, self).__getstate__(),
4337 **{"allowable_chars": self._allowable_chars}
4340 def __setstate__(self, state):
4341 super(PrintableString, self).__setstate__(state)
4342 self._allowable_chars = state.allowable_chars
4353 return self.__class__(
4356 (self._bound_min, self._bound_max)
4357 if bounds is None else bounds
4359 impl=self.tag if impl is None else impl,
4360 expl=self._expl if expl is None else expl,
4361 default=self.default if default is None else default,
4362 optional=self.optional if optional is None else optional,
4363 allow_asterisk=self.allow_asterisk,
4364 allow_ampersand=self.allow_ampersand,
4368 class TeletexString(CommonString):
4370 tag_default = tag_encode(20)
4372 asn1_type_name = "TeletexString"
4375 class T61String(TeletexString):
4377 asn1_type_name = "T61String"
4380 class VideotexString(CommonString):
4382 tag_default = tag_encode(21)
4383 encoding = "iso-8859-1"
4384 asn1_type_name = "VideotexString"
4387 class IA5String(CommonString):
4389 tag_default = tag_encode(22)
4391 asn1_type_name = "IA5"
4394 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4395 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4396 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4399 class VisibleString(CommonString):
4401 tag_default = tag_encode(26)
4403 asn1_type_name = "VisibleString"
4406 UTCTimeState = namedtuple(
4408 OctetStringState._fields + ("ber_raw",),
4413 def str_to_time_fractions(value):
4415 year, v = (v // 10**10), (v % 10**10)
4416 month, v = (v // 10**8), (v % 10**8)
4417 day, v = (v // 10**6), (v % 10**6)
4418 hour, v = (v // 10**4), (v % 10**4)
4419 minute, second = (v // 100), (v % 100)
4420 return year, month, day, hour, minute, second
4423 class UTCTime(VisibleString):
4424 """``UTCTime`` datetime type
4426 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4427 UTCTime UTCTime 2017-09-30T22:07:50
4433 datetime.datetime(2017, 9, 30, 22, 7, 50)
4434 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4435 datetime.datetime(1957, 9, 30, 22, 7, 50)
4437 If BER encoded value was met, then ``ber_raw`` attribute will hold
4438 its raw representation.
4442 Pay attention that UTCTime can not hold full year, so all years
4443 having < 50 years are treated as 20xx, 19xx otherwise, according
4444 to X.509 recommendation.
4448 No strict validation of UTC offsets are made, but very crude:
4450 * minutes are not exceeding 60
4451 * offset value is not exceeding 14 hours
4453 __slots__ = ("ber_raw",)
4454 tag_default = tag_encode(23)
4456 asn1_type_name = "UTCTime"
4457 evgen_mode_skip_value = False
4467 bounds=None, # dummy argument, workability for OctetString.decode
4471 :param value: set the value. Either datetime type, or
4472 :py:class:`pyderasn.UTCTime` object
4473 :param bytes impl: override default tag with ``IMPLICIT`` one
4474 :param bytes expl: override default tag with ``EXPLICIT`` one
4475 :param default: set default value. Type same as in ``value``
4476 :param bool optional: is object ``OPTIONAL`` in sequence
4478 super(UTCTime, self).__init__(
4479 None, None, impl, expl, None, optional, _decoded, ctx,
4483 if value is not None:
4484 self._value, self.ber_raw = self._value_sanitize(value, ctx)
4485 self.ber_encoded = self.ber_raw is not None
4486 if default is not None:
4487 default, _ = self._value_sanitize(default)
4488 self.default = self.__class__(
4493 if self._value is None:
4494 self._value = default
4496 self.optional = optional
4498 def _strptime_bered(self, value):
4499 year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
4502 raise ValueError("no timezone")
4503 year += 2000 if year < 50 else 1900
4504 decoded = datetime(year, month, day, hour, minute)
4506 if value[-1] == "Z":
4510 raise ValueError("invalid UTC offset")
4511 if value[-5] == "-":
4513 elif value[-5] == "+":
4516 raise ValueError("invalid UTC offset")
4517 v = pureint(value[-4:])
4518 offset, v = (60 * (v % 100)), v // 100
4520 raise ValueError("invalid UTC offset minutes")
4522 if offset > 14 * 3600:
4523 raise ValueError("too big UTC offset")
4527 return offset, decoded
4529 raise ValueError("invalid UTC offset seconds")
4530 seconds = pureint(value)
4532 raise ValueError("invalid seconds value")
4533 return offset, decoded + timedelta(seconds=seconds)
4535 def _strptime(self, value):
4536 # datetime.strptime's format: %y%m%d%H%M%SZ
4537 if len(value) != LEN_YYMMDDHHMMSSZ:
4538 raise ValueError("invalid UTCTime length")
4539 if value[-1] != "Z":
4540 raise ValueError("non UTC timezone")
4541 year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
4542 year += 2000 if year < 50 else 1900
4543 return datetime(year, month, day, hour, minute, second)
4545 def _dt_sanitize(self, value):
4546 if value.year < 1950 or value.year > 2049:
4547 raise ValueError("UTCTime can hold only 1950-2049 years")
4548 return value.replace(microsecond=0)
4550 def _value_sanitize(self, value, ctx=None):
4551 if value.__class__ == binary_type:
4553 value_decoded = value.decode("ascii")
4554 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4555 raise DecodeError("invalid UTCTime encoding: %r" % err)
4558 return self._strptime(value_decoded), None
4559 except (TypeError, ValueError) as _err:
4561 if (ctx is not None) and ctx.get("bered", False):
4563 offset, _value = self._strptime_bered(value_decoded)
4564 _value = _value - timedelta(seconds=offset)
4565 return self._dt_sanitize(_value), value
4566 except (TypeError, ValueError, OverflowError) as _err:
4569 "invalid %s format: %r" % (self.asn1_type_name, err),
4570 klass=self.__class__,
4572 if isinstance(value, self.__class__):
4573 return value._value, None
4574 if value.__class__ == datetime:
4575 return self._dt_sanitize(value), None
4576 raise InvalidValueType((self.__class__, datetime))
4578 def _pp_value(self):
4580 value = self._value.isoformat()
4581 if self.ber_encoded:
4582 value += " (%s)" % self.ber_raw
4585 def __unicode__(self):
4587 value = self._value.isoformat()
4588 if self.ber_encoded:
4589 value += " (%s)" % self.ber_raw
4591 return text_type(self._pp_value())
4593 def __getstate__(self):
4594 return UTCTimeState(
4595 *super(UTCTime, self).__getstate__(),
4596 **{"ber_raw": self.ber_raw}
4599 def __setstate__(self, state):
4600 super(UTCTime, self).__setstate__(state)
4601 self.ber_raw = state.ber_raw
4603 def __bytes__(self):
4604 self._assert_ready()
4605 return self._encode_time()
4607 def __eq__(self, their):
4608 if their.__class__ == binary_type:
4609 return self._encode_time() == their
4610 if their.__class__ == datetime:
4611 return self.todatetime() == their
4612 if not isinstance(their, self.__class__):
4615 self._value == their._value and
4616 self.tag == their.tag and
4617 self._expl == their._expl
4620 def _encode_time(self):
4621 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4624 self._assert_ready()
4625 value = self._encode_time()
4626 return b"".join((self.tag, len_encode(len(value)), value))
4628 def _encode_cer(self, writer):
4629 write_full(writer, self._encode())
4631 def todatetime(self):
4635 return pp_console_row(next(self.pps()))
4637 def pps(self, decode_path=()):
4640 asn1_type_name=self.asn1_type_name,
4641 obj_name=self.__class__.__name__,
4642 decode_path=decode_path,
4643 value=self._pp_value(),
4644 optional=self.optional,
4645 default=self == self.default,
4646 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4647 expl=None if self._expl is None else tag_decode(self._expl),
4652 expl_offset=self.expl_offset if self.expled else None,
4653 expl_tlen=self.expl_tlen if self.expled else None,
4654 expl_llen=self.expl_llen if self.expled else None,
4655 expl_vlen=self.expl_vlen if self.expled else None,
4656 expl_lenindef=self.expl_lenindef,
4657 ber_encoded=self.ber_encoded,
4660 for pp in self.pps_lenindef(decode_path):
4664 class GeneralizedTime(UTCTime):
4665 """``GeneralizedTime`` datetime type
4667 This type is similar to :py:class:`pyderasn.UTCTime`.
4669 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4670 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4672 '20170930220750.000123Z'
4673 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4674 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4678 Only microsecond fractions are supported in DER encoding.
4679 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4680 higher precision values.
4684 BER encoded data can loss information (accuracy) during decoding
4685 because of float transformations.
4689 Local times (without explicit timezone specification) are treated
4690 as UTC one, no transformations are made.
4694 Zero year is unsupported.
4697 tag_default = tag_encode(24)
4698 asn1_type_name = "GeneralizedTime"
4700 def _dt_sanitize(self, value):
4703 def _strptime_bered(self, value):
4704 if len(value) < 4 + 3 * 2:
4705 raise ValueError("invalid GeneralizedTime")
4706 year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
4707 decoded = datetime(year, month, day, hour)
4708 offset, value = 0, value[10:]
4710 return offset, decoded
4711 if value[-1] == "Z":
4714 for char, sign in (("-", -1), ("+", 1)):
4715 idx = value.rfind(char)
4718 offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
4719 v = pureint(offset_raw)
4720 if len(offset_raw) == 4:
4721 offset, v = (60 * (v % 100)), v // 100
4723 raise ValueError("invalid UTC offset minutes")
4724 elif len(offset_raw) == 2:
4727 raise ValueError("invalid UTC offset")
4729 if offset > 14 * 3600:
4730 raise ValueError("too big UTC offset")
4734 return offset, decoded
4735 if value[0] in DECIMAL_SIGNS:
4737 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4740 raise ValueError("stripped minutes")
4741 decoded += timedelta(seconds=60 * pureint(value[:2]))
4744 return offset, decoded
4745 if value[0] in DECIMAL_SIGNS:
4747 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4750 raise ValueError("stripped seconds")
4751 decoded += timedelta(seconds=pureint(value[:2]))
4754 return offset, decoded
4755 if value[0] not in DECIMAL_SIGNS:
4756 raise ValueError("invalid format after seconds")
4758 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4761 def _strptime(self, value):
4763 if l == LEN_YYYYMMDDHHMMSSZ:
4764 # datetime.strptime's format: %Y%m%d%H%M%SZ
4765 if value[-1] != "Z":
4766 raise ValueError("non UTC timezone")
4767 return datetime(*str_to_time_fractions(value[:-1]))
4768 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4769 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4770 if value[-1] != "Z":
4771 raise ValueError("non UTC timezone")
4772 if value[14] != ".":
4773 raise ValueError("no fractions separator")
4776 raise ValueError("trailing zero")
4779 raise ValueError("only microsecond fractions are supported")
4780 us = pureint(us + ("0" * (6 - us_len)))
4781 year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
4782 return datetime(year, month, day, hour, minute, second, us)
4783 raise ValueError("invalid GeneralizedTime length")
4785 def _encode_time(self):
4787 encoded = value.strftime("%Y%m%d%H%M%S")
4788 if value.microsecond > 0:
4789 encoded += (".%06d" % value.microsecond).rstrip("0")
4790 return (encoded + "Z").encode("ascii")
4793 class GraphicString(CommonString):
4795 tag_default = tag_encode(25)
4796 encoding = "iso-8859-1"
4797 asn1_type_name = "GraphicString"
4800 class ISO646String(VisibleString):
4802 asn1_type_name = "ISO646String"
4805 class GeneralString(CommonString):
4807 tag_default = tag_encode(27)
4808 encoding = "iso-8859-1"
4809 asn1_type_name = "GeneralString"
4812 class UniversalString(CommonString):
4814 tag_default = tag_encode(28)
4815 encoding = "utf-32-be"
4816 asn1_type_name = "UniversalString"
4819 class BMPString(CommonString):
4821 tag_default = tag_encode(30)
4822 encoding = "utf-16-be"
4823 asn1_type_name = "BMPString"
4826 ChoiceState = namedtuple(
4828 BasicState._fields + ("specs", "value",),
4834 """``CHOICE`` special type
4838 class GeneralName(Choice):
4840 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4841 ("dNSName", IA5String(impl=tag_ctxp(2))),
4844 >>> gn = GeneralName()
4846 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4847 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4848 >>> gn["dNSName"] = IA5String("bar.baz")
4849 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4850 >>> gn["rfc822Name"]
4853 [2] IA5String IA5 bar.baz
4856 >>> gn.value == gn["dNSName"]
4859 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4861 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4862 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4864 __slots__ = ("specs",)
4866 asn1_type_name = "CHOICE"
4879 :param value: set the value. Either ``(choice, value)`` tuple, or
4880 :py:class:`pyderasn.Choice` object
4881 :param bytes impl: can not be set, do **not** use it
4882 :param bytes expl: override default tag with ``EXPLICIT`` one
4883 :param default: set default value. Type same as in ``value``
4884 :param bool optional: is object ``OPTIONAL`` in sequence
4886 if impl is not None:
4887 raise ValueError("no implicit tag allowed for CHOICE")
4888 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4890 schema = getattr(self, "schema", ())
4891 if len(schema) == 0:
4892 raise ValueError("schema must be specified")
4894 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
4897 if value is not None:
4898 self._value = self._value_sanitize(value)
4899 if default is not None:
4900 default_value = self._value_sanitize(default)
4901 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4902 default_obj.specs = self.specs
4903 default_obj._value = default_value
4904 self.default = default_obj
4906 self._value = copy(default_obj._value)
4907 if self._expl is not None:
4908 tag_class, _, tag_num = tag_decode(self._expl)
4909 self._tag_order = (tag_class, tag_num)
4911 def _value_sanitize(self, value):
4912 if (value.__class__ == tuple) and len(value) == 2:
4914 spec = self.specs.get(choice)
4916 raise ObjUnknown(choice)
4917 if not isinstance(obj, spec.__class__):
4918 raise InvalidValueType((spec,))
4919 return (choice, spec(obj))
4920 if isinstance(value, self.__class__):
4922 raise InvalidValueType((self.__class__, tuple))
4926 return self._value is not None and self._value[1].ready
4930 return self.expl_lenindef or (
4931 (self._value is not None) and
4932 self._value[1].bered
4935 def __getstate__(self):
4953 def __setstate__(self, state):
4954 super(Choice, self).__setstate__(state)
4955 self.specs = state.specs
4956 self._value = state.value
4958 def __eq__(self, their):
4959 if (their.__class__ == tuple) and len(their) == 2:
4960 return self._value == their
4961 if not isinstance(their, self.__class__):
4964 self.specs == their.specs and
4965 self._value == their._value
4975 return self.__class__(
4978 expl=self._expl if expl is None else expl,
4979 default=self.default if default is None else default,
4980 optional=self.optional if optional is None else optional,
4985 """Name of the choice
4987 self._assert_ready()
4988 return self._value[0]
4992 """Value of underlying choice
4994 self._assert_ready()
4995 return self._value[1]
4998 def tag_order(self):
4999 self._assert_ready()
5000 return self._value[1].tag_order if self._tag_order is None else self._tag_order
5003 def tag_order_cer(self):
5004 return min(v.tag_order_cer for v in itervalues(self.specs))
5006 def __getitem__(self, key):
5007 if key not in self.specs:
5008 raise ObjUnknown(key)
5009 if self._value is None:
5011 choice, value = self._value
5016 def __setitem__(self, key, value):
5017 spec = self.specs.get(key)
5019 raise ObjUnknown(key)
5020 if not isinstance(value, spec.__class__):
5021 raise InvalidValueType((spec.__class__,))
5022 self._value = (key, spec(value))
5030 return self._value[1].decoded if self.ready else False
5033 self._assert_ready()
5034 return self._value[1].encode()
5036 def _encode_cer(self, writer):
5037 self._assert_ready()
5038 self._value[1].encode_cer(writer)
5040 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5041 for choice, spec in iteritems(self.specs):
5042 sub_decode_path = decode_path + (choice,)
5048 decode_path=sub_decode_path,
5051 _ctx_immutable=False,
5058 klass=self.__class__,
5059 decode_path=decode_path,
5062 if tag_only: # pragma: no cover
5066 for _decode_path, value, tail in spec.decode_evgen(
5070 decode_path=sub_decode_path,
5072 _ctx_immutable=False,
5074 yield _decode_path, value, tail
5076 _, value, tail = next(spec.decode_evgen(
5080 decode_path=sub_decode_path,
5082 _ctx_immutable=False,
5085 obj = self.__class__(
5088 default=self.default,
5089 optional=self.optional,
5090 _decoded=(offset, 0, value.fulllen),
5092 obj._value = (choice, value)
5093 yield decode_path, obj, tail
5096 value = pp_console_row(next(self.pps()))
5098 value = "%s[%r]" % (value, self.value)
5101 def pps(self, decode_path=()):
5104 asn1_type_name=self.asn1_type_name,
5105 obj_name=self.__class__.__name__,
5106 decode_path=decode_path,
5107 value=self.choice if self.ready else None,
5108 optional=self.optional,
5109 default=self == self.default,
5110 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5111 expl=None if self._expl is None else tag_decode(self._expl),
5116 expl_lenindef=self.expl_lenindef,
5120 yield self.value.pps(decode_path=decode_path + (self.choice,))
5121 for pp in self.pps_lenindef(decode_path):
5125 class PrimitiveTypes(Choice):
5126 """Predefined ``CHOICE`` for all generic primitive types
5128 It could be useful for general decoding of some unspecified values:
5130 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
5131 OCTET STRING 3 bytes 666f6f
5132 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
5136 schema = tuple((klass.__name__, klass()) for klass in (
5160 AnyState = namedtuple(
5162 BasicState._fields + ("value", "defined"),
5168 """``ANY`` special type
5170 >>> Any(Integer(-123))
5171 ANY INTEGER -123 (0X:7B)
5172 >>> a = Any(OctetString(b"hello world").encode())
5173 ANY 040b68656c6c6f20776f726c64
5174 >>> hexenc(bytes(a))
5175 b'0x040x0bhello world'
5177 __slots__ = ("defined",)
5178 tag_default = tag_encode(0)
5179 asn1_type_name = "ANY"
5189 :param value: set the value. Either any kind of pyderasn's
5190 **ready** object, or bytes. Pay attention that
5191 **no** validation is performed if raw binary value
5192 is valid TLV, except just tag decoding
5193 :param bytes expl: override default tag with ``EXPLICIT`` one
5194 :param bool optional: is object ``OPTIONAL`` in sequence
5196 super(Any, self).__init__(None, expl, None, optional, _decoded)
5200 value = self._value_sanitize(value)
5202 if self._expl is None:
5203 if value.__class__ == binary_type:
5204 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5206 tag_class, tag_num = value.tag_order
5208 tag_class, _, tag_num = tag_decode(self._expl)
5209 self._tag_order = (tag_class, tag_num)
5212 def _value_sanitize(self, value):
5213 if value.__class__ == binary_type:
5215 raise ValueError("Any value can not be empty")
5217 if isinstance(value, self.__class__):
5219 if not isinstance(value, Obj):
5220 raise InvalidValueType((self.__class__, Obj, binary_type))
5225 return self._value is not None
5228 def tag_order(self):
5229 self._assert_ready()
5230 return self._tag_order
5234 if self.expl_lenindef or self.lenindef:
5236 if self.defined is None:
5238 return self.defined[1].bered
5240 def __getstate__(self):
5258 def __setstate__(self, state):
5259 super(Any, self).__setstate__(state)
5260 self._value = state.value
5261 self.defined = state.defined
5263 def __eq__(self, their):
5264 if their.__class__ == binary_type:
5265 if self._value.__class__ == binary_type:
5266 return self._value == their
5267 return self._value.encode() == their
5268 if issubclass(their.__class__, Any):
5269 if self.ready and their.ready:
5270 return bytes(self) == bytes(their)
5271 return self.ready == their.ready
5280 return self.__class__(
5282 expl=self._expl if expl is None else expl,
5283 optional=self.optional if optional is None else optional,
5286 def __bytes__(self):
5287 self._assert_ready()
5289 if value.__class__ == binary_type:
5291 return self._value.encode()
5298 self._assert_ready()
5300 if value.__class__ == binary_type:
5302 return value.encode()
5304 def _encode_cer(self, writer):
5305 self._assert_ready()
5307 if value.__class__ == binary_type:
5308 write_full(writer, value)
5310 value.encode_cer(writer)
5312 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5314 t, tlen, lv = tag_strip(tlv)
5315 except DecodeError as err:
5316 raise err.__class__(
5318 klass=self.__class__,
5319 decode_path=decode_path,
5323 l, llen, v = len_decode(lv)
5324 except LenIndefForm as err:
5325 if not ctx.get("bered", False):
5326 raise err.__class__(
5328 klass=self.__class__,
5329 decode_path=decode_path,
5332 llen, vlen, v = 1, 0, lv[1:]
5333 sub_offset = offset + tlen + llen
5335 while v[:EOC_LEN].tobytes() != EOC:
5336 chunk, v = Any().decode(
5339 decode_path=decode_path + (str(chunk_i),),
5342 _ctx_immutable=False,
5344 vlen += chunk.tlvlen
5345 sub_offset += chunk.tlvlen
5347 tlvlen = tlen + llen + vlen + EOC_LEN
5348 obj = self.__class__(
5349 value=None if evgen_mode else tlv[:tlvlen].tobytes(),
5351 optional=self.optional,
5352 _decoded=(offset, 0, tlvlen),
5355 obj.tag = t.tobytes()
5356 yield decode_path, obj, v[EOC_LEN:]
5358 except DecodeError as err:
5359 raise err.__class__(
5361 klass=self.__class__,
5362 decode_path=decode_path,
5366 raise NotEnoughData(
5367 "encoded length is longer than data",
5368 klass=self.__class__,
5369 decode_path=decode_path,
5372 tlvlen = tlen + llen + l
5373 v, tail = tlv[:tlvlen], v[l:]
5374 obj = self.__class__(
5375 value=None if evgen_mode else v.tobytes(),
5377 optional=self.optional,
5378 _decoded=(offset, 0, tlvlen),
5380 obj.tag = t.tobytes()
5381 yield decode_path, obj, tail
5384 return pp_console_row(next(self.pps()))
5386 def pps(self, decode_path=()):
5390 elif value.__class__ == binary_type:
5396 asn1_type_name=self.asn1_type_name,
5397 obj_name=self.__class__.__name__,
5398 decode_path=decode_path,
5400 blob=self._value if self._value.__class__ == binary_type else None,
5401 optional=self.optional,
5402 default=self == self.default,
5403 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5404 expl=None if self._expl is None else tag_decode(self._expl),
5409 expl_offset=self.expl_offset if self.expled else None,
5410 expl_tlen=self.expl_tlen if self.expled else None,
5411 expl_llen=self.expl_llen if self.expled else None,
5412 expl_vlen=self.expl_vlen if self.expled else None,
5413 expl_lenindef=self.expl_lenindef,
5414 lenindef=self.lenindef,
5417 defined_by, defined = self.defined or (None, None)
5418 if defined_by is not None:
5420 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5422 for pp in self.pps_lenindef(decode_path):
5426 ########################################################################
5427 # ASN.1 constructed types
5428 ########################################################################
5430 def get_def_by_path(defines_by_path, sub_decode_path):
5431 """Get define by decode path
5433 for path, define in defines_by_path:
5434 if len(path) != len(sub_decode_path):
5436 for p1, p2 in zip(path, sub_decode_path):
5437 if (not p1 is any) and (p1 != p2):
5443 def abs_decode_path(decode_path, rel_path):
5444 """Create an absolute decode path from current and relative ones
5446 :param decode_path: current decode path, starting point. Tuple of strings
5447 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5448 If first tuple's element is "/", then treat it as
5449 an absolute path, ignoring ``decode_path`` as
5450 starting point. Also this tuple can contain ".."
5451 elements, stripping the leading element from
5454 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5455 ("foo", "bar", "baz", "whatever")
5456 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5458 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5461 if rel_path[0] == "/":
5463 if rel_path[0] == "..":
5464 return abs_decode_path(decode_path[:-1], rel_path[1:])
5465 return decode_path + rel_path
5468 SequenceState = namedtuple(
5470 BasicState._fields + ("specs", "value",),
5475 class Sequence(Obj):
5476 """``SEQUENCE`` structure type
5478 You have to make specification of sequence::
5480 class Extension(Sequence):
5482 ("extnID", ObjectIdentifier()),
5483 ("critical", Boolean(default=False)),
5484 ("extnValue", OctetString()),
5487 Then, you can work with it as with dictionary.
5489 >>> ext = Extension()
5490 >>> Extension().specs
5492 ('extnID', OBJECT IDENTIFIER),
5493 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5494 ('extnValue', OCTET STRING),
5496 >>> ext["extnID"] = "1.2.3"
5497 Traceback (most recent call last):
5498 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5499 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5501 You can determine if sequence is ready to be encoded:
5506 Traceback (most recent call last):
5507 pyderasn.ObjNotReady: object is not ready: extnValue
5508 >>> ext["extnValue"] = OctetString(b"foobar")
5512 Value you want to assign, must have the same **type** as in
5513 corresponding specification, but it can have different tags,
5514 optional/default attributes -- they will be taken from specification
5517 class TBSCertificate(Sequence):
5519 ("version", Version(expl=tag_ctxc(0), default="v1")),
5522 >>> tbs = TBSCertificate()
5523 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5525 Assign ``None`` to remove value from sequence.
5527 You can set values in Sequence during its initialization:
5529 >>> AlgorithmIdentifier((
5530 ("algorithm", ObjectIdentifier("1.2.3")),
5531 ("parameters", Any(Null()))
5533 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5535 You can determine if value exists/set in the sequence and take its value:
5537 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5540 OBJECT IDENTIFIER 1.2.3
5542 But pay attention that if value has default, then it won't be (not
5543 in) in the sequence (because ``DEFAULT`` must not be encoded in
5544 DER), but you can read its value:
5546 >>> "critical" in ext, ext["critical"]
5547 (False, BOOLEAN False)
5548 >>> ext["critical"] = Boolean(True)
5549 >>> "critical" in ext, ext["critical"]
5550 (True, BOOLEAN True)
5552 All defaulted values are always optional.
5554 .. _allow_default_values_ctx:
5556 DER prohibits default value encoding and will raise an error if
5557 default value is unexpectedly met during decode.
5558 If :ref:`bered <bered_ctx>` context option is set, then no error
5559 will be raised, but ``bered`` attribute set. You can disable strict
5560 defaulted values existence validation by setting
5561 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5565 Check for default value existence is not performed in
5566 ``evgen_mode``, because previously decoded values are not stored
5567 in memory, to be able to compare them.
5569 Two sequences are equal if they have equal specification (schema),
5570 implicit/explicit tagging and the same values.
5572 __slots__ = ("specs",)
5573 tag_default = tag_encode(form=TagFormConstructed, num=16)
5574 asn1_type_name = "SEQUENCE"
5586 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5588 schema = getattr(self, "schema", ())
5590 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
5593 if value is not None:
5594 if issubclass(value.__class__, Sequence):
5595 self._value = value._value
5596 elif hasattr(value, "__iter__"):
5597 for seq_key, seq_value in value:
5598 self[seq_key] = seq_value
5600 raise InvalidValueType((Sequence,))
5601 if default is not None:
5602 if not issubclass(default.__class__, Sequence):
5603 raise InvalidValueType((Sequence,))
5604 default_value = default._value
5605 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5606 default_obj.specs = self.specs
5607 default_obj._value = default_value
5608 self.default = default_obj
5610 self._value = copy(default_obj._value)
5614 for name, spec in iteritems(self.specs):
5615 value = self._value.get(name)
5626 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5628 return any(value.bered for value in itervalues(self._value))
5630 def __getstate__(self):
5631 return SequenceState(
5645 {k: copy(v) for k, v in iteritems(self._value)},
5648 def __setstate__(self, state):
5649 super(Sequence, self).__setstate__(state)
5650 self.specs = state.specs
5651 self._value = state.value
5653 def __eq__(self, their):
5654 if not isinstance(their, self.__class__):
5657 self.specs == their.specs and
5658 self.tag == their.tag and
5659 self._expl == their._expl and
5660 self._value == their._value
5671 return self.__class__(
5674 impl=self.tag if impl is None else impl,
5675 expl=self._expl if expl is None else expl,
5676 default=self.default if default is None else default,
5677 optional=self.optional if optional is None else optional,
5680 def __contains__(self, key):
5681 return key in self._value
5683 def __setitem__(self, key, value):
5684 spec = self.specs.get(key)
5686 raise ObjUnknown(key)
5688 self._value.pop(key, None)
5690 if not isinstance(value, spec.__class__):
5691 raise InvalidValueType((spec.__class__,))
5692 value = spec(value=value)
5693 if spec.default is not None and value == spec.default:
5694 self._value.pop(key, None)
5696 self._value[key] = value
5698 def __getitem__(self, key):
5699 value = self._value.get(key)
5700 if value is not None:
5702 spec = self.specs.get(key)
5704 raise ObjUnknown(key)
5705 if spec.default is not None:
5709 def _values_for_encoding(self):
5710 for name, spec in iteritems(self.specs):
5711 value = self._value.get(name)
5715 raise ObjNotReady(name)
5719 v = b"".join(v.encode() for v in self._values_for_encoding())
5720 return b"".join((self.tag, len_encode(len(v)), v))
5722 def _encode_cer(self, writer):
5723 write_full(writer, self.tag + LENINDEF)
5724 for v in self._values_for_encoding():
5725 v.encode_cer(writer)
5726 write_full(writer, EOC)
5728 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5730 t, tlen, lv = tag_strip(tlv)
5731 except DecodeError as err:
5732 raise err.__class__(
5734 klass=self.__class__,
5735 decode_path=decode_path,
5740 klass=self.__class__,
5741 decode_path=decode_path,
5744 if tag_only: # pragma: no cover
5748 ctx_bered = ctx.get("bered", False)
5750 l, llen, v = len_decode(lv)
5751 except LenIndefForm as err:
5753 raise err.__class__(
5755 klass=self.__class__,
5756 decode_path=decode_path,
5759 l, llen, v = 0, 1, lv[1:]
5761 except DecodeError as err:
5762 raise err.__class__(
5764 klass=self.__class__,
5765 decode_path=decode_path,
5769 raise NotEnoughData(
5770 "encoded length is longer than data",
5771 klass=self.__class__,
5772 decode_path=decode_path,
5776 v, tail = v[:l], v[l:]
5778 sub_offset = offset + tlen + llen
5781 ctx_allow_default_values = ctx.get("allow_default_values", False)
5782 for name, spec in iteritems(self.specs):
5783 if spec.optional and (
5784 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5788 sub_decode_path = decode_path + (name,)
5791 for _decode_path, value, v_tail in spec.decode_evgen(
5795 decode_path=sub_decode_path,
5797 _ctx_immutable=False,
5799 yield _decode_path, value, v_tail
5801 _, value, v_tail = next(spec.decode_evgen(
5805 decode_path=sub_decode_path,
5807 _ctx_immutable=False,
5810 except TagMismatch as err:
5811 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5815 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5816 if not evgen_mode and defined is not None:
5817 defined_by, defined_spec = defined
5818 if issubclass(value.__class__, SequenceOf):
5819 for i, _value in enumerate(value):
5820 sub_sub_decode_path = sub_decode_path + (
5822 DecodePathDefBy(defined_by),
5824 defined_value, defined_tail = defined_spec.decode(
5825 memoryview(bytes(_value)),
5827 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5828 if value.expled else (value.tlen + value.llen)
5831 decode_path=sub_sub_decode_path,
5833 _ctx_immutable=False,
5835 if len(defined_tail) > 0:
5838 klass=self.__class__,
5839 decode_path=sub_sub_decode_path,
5842 _value.defined = (defined_by, defined_value)
5844 defined_value, defined_tail = defined_spec.decode(
5845 memoryview(bytes(value)),
5847 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5848 if value.expled else (value.tlen + value.llen)
5851 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5853 _ctx_immutable=False,
5855 if len(defined_tail) > 0:
5858 klass=self.__class__,
5859 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5862 value.defined = (defined_by, defined_value)
5864 value_len = value.fulllen
5866 sub_offset += value_len
5869 if spec.default is not None and value == spec.default:
5870 # This will not work in evgen_mode
5871 if ctx_bered or ctx_allow_default_values:
5875 "DEFAULT value met",
5876 klass=self.__class__,
5877 decode_path=sub_decode_path,
5880 values[name] = value
5881 spec_defines = getattr(spec, "defines", ())
5882 if len(spec_defines) == 0:
5883 defines_by_path = ctx.get("defines_by_path", ())
5884 if len(defines_by_path) > 0:
5885 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5886 if spec_defines is not None and len(spec_defines) > 0:
5887 for rel_path, schema in spec_defines:
5888 defined = schema.get(value, None)
5889 if defined is not None:
5890 ctx.setdefault("_defines", []).append((
5891 abs_decode_path(sub_decode_path[:-1], rel_path),
5895 if v[:EOC_LEN].tobytes() != EOC:
5898 klass=self.__class__,
5899 decode_path=decode_path,
5907 klass=self.__class__,
5908 decode_path=decode_path,
5911 obj = self.__class__(
5915 default=self.default,
5916 optional=self.optional,
5917 _decoded=(offset, llen, vlen),
5920 obj.lenindef = lenindef
5921 obj.ber_encoded = ber_encoded
5922 yield decode_path, obj, tail
5925 value = pp_console_row(next(self.pps()))
5927 for name in self.specs:
5928 _value = self._value.get(name)
5931 cols.append("%s: %s" % (name, repr(_value)))
5932 return "%s[%s]" % (value, "; ".join(cols))
5934 def pps(self, decode_path=()):
5937 asn1_type_name=self.asn1_type_name,
5938 obj_name=self.__class__.__name__,
5939 decode_path=decode_path,
5940 optional=self.optional,
5941 default=self == self.default,
5942 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5943 expl=None if self._expl is None else tag_decode(self._expl),
5948 expl_offset=self.expl_offset if self.expled else None,
5949 expl_tlen=self.expl_tlen if self.expled else None,
5950 expl_llen=self.expl_llen if self.expled else None,
5951 expl_vlen=self.expl_vlen if self.expled else None,
5952 expl_lenindef=self.expl_lenindef,
5953 lenindef=self.lenindef,
5954 ber_encoded=self.ber_encoded,
5957 for name in self.specs:
5958 value = self._value.get(name)
5961 yield value.pps(decode_path=decode_path + (name,))
5962 for pp in self.pps_lenindef(decode_path):
5966 class Set(Sequence):
5967 """``SET`` structure type
5969 Its usage is identical to :py:class:`pyderasn.Sequence`.
5971 .. _allow_unordered_set_ctx:
5973 DER prohibits unordered values encoding and will raise an error
5974 during decode. If :ref:`bered <bered_ctx>` context option is set,
5975 then no error will occur. Also you can disable strict values
5976 ordering check by setting ``"allow_unordered_set": True``
5977 :ref:`context <ctx>` option.
5980 tag_default = tag_encode(form=TagFormConstructed, num=17)
5981 asn1_type_name = "SET"
5984 v = b"".join(value.encode() for value in sorted(
5985 self._values_for_encoding(),
5986 key=attrgetter("tag_order"),
5988 return b"".join((self.tag, len_encode(len(v)), v))
5990 def _encode_cer(self, writer):
5991 write_full(writer, self.tag + LENINDEF)
5993 self._values_for_encoding(),
5994 key=attrgetter("tag_order_cer"),
5996 v.encode_cer(writer)
5997 write_full(writer, EOC)
5999 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
6001 t, tlen, lv = tag_strip(tlv)
6002 except DecodeError as err:
6003 raise err.__class__(
6005 klass=self.__class__,
6006 decode_path=decode_path,
6011 klass=self.__class__,
6012 decode_path=decode_path,
6019 ctx_bered = ctx.get("bered", False)
6021 l, llen, v = len_decode(lv)
6022 except LenIndefForm as err:
6024 raise err.__class__(
6026 klass=self.__class__,
6027 decode_path=decode_path,
6030 l, llen, v = 0, 1, lv[1:]
6032 except DecodeError as err:
6033 raise err.__class__(
6035 klass=self.__class__,
6036 decode_path=decode_path,
6040 raise NotEnoughData(
6041 "encoded length is longer than data",
6042 klass=self.__class__,
6046 v, tail = v[:l], v[l:]
6048 sub_offset = offset + tlen + llen
6051 ctx_allow_default_values = ctx.get("allow_default_values", False)
6052 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6053 tag_order_prev = (0, 0)
6054 _specs_items = copy(self.specs)
6057 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6059 for name, spec in iteritems(_specs_items):
6060 sub_decode_path = decode_path + (name,)
6066 decode_path=sub_decode_path,
6069 _ctx_immutable=False,
6076 klass=self.__class__,
6077 decode_path=decode_path,
6081 for _decode_path, value, v_tail in spec.decode_evgen(
6085 decode_path=sub_decode_path,
6087 _ctx_immutable=False,
6089 yield _decode_path, value, v_tail
6091 _, value, v_tail = next(spec.decode_evgen(
6095 decode_path=sub_decode_path,
6097 _ctx_immutable=False,
6100 value_tag_order = value.tag_order
6101 value_len = value.fulllen
6102 if tag_order_prev >= value_tag_order:
6103 if ctx_bered or ctx_allow_unordered_set:
6107 "unordered " + self.asn1_type_name,
6108 klass=self.__class__,
6109 decode_path=sub_decode_path,
6112 if spec.default is None or value != spec.default:
6114 elif ctx_bered or ctx_allow_default_values:
6118 "DEFAULT value met",
6119 klass=self.__class__,
6120 decode_path=sub_decode_path,
6123 values[name] = value
6124 del _specs_items[name]
6125 tag_order_prev = value_tag_order
6126 sub_offset += value_len
6130 obj = self.__class__(
6134 default=self.default,
6135 optional=self.optional,
6136 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6139 if v[:EOC_LEN].tobytes() != EOC:
6142 klass=self.__class__,
6143 decode_path=decode_path,
6148 for name, spec in iteritems(self.specs):
6149 if name not in values and not spec.optional:
6151 "%s value is not ready" % name,
6152 klass=self.__class__,
6153 decode_path=decode_path,
6158 obj.ber_encoded = ber_encoded
6159 yield decode_path, obj, tail
6162 SequenceOfState = namedtuple(
6164 BasicState._fields + ("spec", "value", "bound_min", "bound_max"),
6169 class SequenceOf(Obj):
6170 """``SEQUENCE OF`` sequence type
6172 For that kind of type you must specify the object it will carry on
6173 (bounds are for example here, not required)::
6175 class Ints(SequenceOf):
6180 >>> ints.append(Integer(123))
6181 >>> ints.append(Integer(234))
6183 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
6184 >>> [int(i) for i in ints]
6186 >>> ints.append(Integer(345))
6187 Traceback (most recent call last):
6188 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
6191 >>> ints[1] = Integer(345)
6193 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
6195 Also you can initialize sequence with preinitialized values:
6197 >>> ints = Ints([Integer(123), Integer(234)])
6199 __slots__ = ("spec", "_bound_min", "_bound_max")
6200 tag_default = tag_encode(form=TagFormConstructed, num=16)
6201 asn1_type_name = "SEQUENCE OF"
6214 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
6216 schema = getattr(self, "schema", None)
6218 raise ValueError("schema must be specified")
6220 self._bound_min, self._bound_max = getattr(
6224 ) if bounds is None else bounds
6226 if value is not None:
6227 self._value = self._value_sanitize(value)
6228 if default is not None:
6229 default_value = self._value_sanitize(default)
6230 default_obj = self.__class__(
6235 default_obj._value = default_value
6236 self.default = default_obj
6238 self._value = copy(default_obj._value)
6240 def _value_sanitize(self, value):
6241 if issubclass(value.__class__, SequenceOf):
6242 value = value._value
6243 elif hasattr(value, "__iter__"):
6246 raise InvalidValueType((self.__class__, iter))
6247 if not self._bound_min <= len(value) <= self._bound_max:
6248 raise BoundsError(self._bound_min, len(value), self._bound_max)
6250 if not isinstance(v, self.spec.__class__):
6251 raise InvalidValueType((self.spec.__class__,))
6256 return all(v.ready for v in self._value)
6260 if self.expl_lenindef or self.lenindef or self.ber_encoded:
6262 return any(v.bered for v in self._value)
6264 def __getstate__(self):
6265 return SequenceOfState(
6279 [copy(v) for v in self._value],
6284 def __setstate__(self, state):
6285 super(SequenceOf, self).__setstate__(state)
6286 self.spec = state.spec
6287 self._value = state.value
6288 self._bound_min = state.bound_min
6289 self._bound_max = state.bound_max
6291 def __eq__(self, their):
6292 if isinstance(their, self.__class__):
6294 self.spec == their.spec and
6295 self.tag == their.tag and
6296 self._expl == their._expl and
6297 self._value == their._value
6299 if hasattr(their, "__iter__"):
6300 return self._value == list(their)
6312 return self.__class__(
6316 (self._bound_min, self._bound_max)
6317 if bounds is None else bounds
6319 impl=self.tag if impl is None else impl,
6320 expl=self._expl if expl is None else expl,
6321 default=self.default if default is None else default,
6322 optional=self.optional if optional is None else optional,
6325 def __contains__(self, key):
6326 return key in self._value
6328 def append(self, value):
6329 if not isinstance(value, self.spec.__class__):
6330 raise InvalidValueType((self.spec.__class__,))
6331 if len(self._value) + 1 > self._bound_max:
6334 len(self._value) + 1,
6337 self._value.append(value)
6340 self._assert_ready()
6341 return iter(self._value)
6344 self._assert_ready()
6345 return len(self._value)
6347 def __setitem__(self, key, value):
6348 if not isinstance(value, self.spec.__class__):
6349 raise InvalidValueType((self.spec.__class__,))
6350 self._value[key] = self.spec(value=value)
6352 def __getitem__(self, key):
6353 return self._value[key]
6355 def _values_for_encoding(self):
6356 return iter(self._value)
6359 v = b"".join(v.encode() for v in self._values_for_encoding())
6360 return b"".join((self.tag, len_encode(len(v)), v))
6362 def _encode_cer(self, writer):
6363 write_full(writer, self.tag + LENINDEF)
6364 for v in self._values_for_encoding():
6365 v.encode_cer(writer)
6366 write_full(writer, EOC)
6376 ordering_check=False,
6379 t, tlen, lv = tag_strip(tlv)
6380 except DecodeError as err:
6381 raise err.__class__(
6383 klass=self.__class__,
6384 decode_path=decode_path,
6389 klass=self.__class__,
6390 decode_path=decode_path,
6397 ctx_bered = ctx.get("bered", False)
6399 l, llen, v = len_decode(lv)
6400 except LenIndefForm as err:
6402 raise err.__class__(
6404 klass=self.__class__,
6405 decode_path=decode_path,
6408 l, llen, v = 0, 1, lv[1:]
6410 except DecodeError as err:
6411 raise err.__class__(
6413 klass=self.__class__,
6414 decode_path=decode_path,
6418 raise NotEnoughData(
6419 "encoded length is longer than data",
6420 klass=self.__class__,
6421 decode_path=decode_path,
6425 v, tail = v[:l], v[l:]
6427 sub_offset = offset + tlen + llen
6430 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6431 value_prev = memoryview(v[:0])
6435 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6437 sub_decode_path = decode_path + (str(_value_count),)
6439 for _decode_path, value, v_tail in spec.decode_evgen(
6443 decode_path=sub_decode_path,
6445 _ctx_immutable=False,
6447 yield _decode_path, value, v_tail
6449 _, value, v_tail = next(spec.decode_evgen(
6453 decode_path=sub_decode_path,
6455 _ctx_immutable=False,
6458 value_len = value.fulllen
6460 if value_prev.tobytes() > v[:value_len].tobytes():
6461 if ctx_bered or ctx_allow_unordered_set:
6465 "unordered " + self.asn1_type_name,
6466 klass=self.__class__,
6467 decode_path=sub_decode_path,
6470 value_prev = v[:value_len]
6473 _value.append(value)
6474 sub_offset += value_len
6477 if evgen_mode and not self._bound_min <= _value_count <= self._bound_max:
6479 msg=str(BoundsError(self._bound_min, _value_count, self._bound_max)),
6480 klass=self.__class__,
6481 decode_path=decode_path,
6485 obj = self.__class__(
6486 value=None if evgen_mode else _value,
6488 bounds=(self._bound_min, self._bound_max),
6491 default=self.default,
6492 optional=self.optional,
6493 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6495 except BoundsError as err:
6498 klass=self.__class__,
6499 decode_path=decode_path,
6503 if v[:EOC_LEN].tobytes() != EOC:
6506 klass=self.__class__,
6507 decode_path=decode_path,
6512 obj.ber_encoded = ber_encoded
6513 yield decode_path, obj, tail
6517 pp_console_row(next(self.pps())),
6518 ", ".join(repr(v) for v in self._value),
6521 def pps(self, decode_path=()):
6524 asn1_type_name=self.asn1_type_name,
6525 obj_name=self.__class__.__name__,
6526 decode_path=decode_path,
6527 optional=self.optional,
6528 default=self == self.default,
6529 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6530 expl=None if self._expl is None else tag_decode(self._expl),
6535 expl_offset=self.expl_offset if self.expled else None,
6536 expl_tlen=self.expl_tlen if self.expled else None,
6537 expl_llen=self.expl_llen if self.expled else None,
6538 expl_vlen=self.expl_vlen if self.expled else None,
6539 expl_lenindef=self.expl_lenindef,
6540 lenindef=self.lenindef,
6541 ber_encoded=self.ber_encoded,
6544 for i, value in enumerate(self._value):
6545 yield value.pps(decode_path=decode_path + (str(i),))
6546 for pp in self.pps_lenindef(decode_path):
6550 class SetOf(SequenceOf):
6551 """``SET OF`` sequence type
6553 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6556 tag_default = tag_encode(form=TagFormConstructed, num=17)
6557 asn1_type_name = "SET OF"
6560 v = b"".join(sorted(v.encode() for v in self._values_for_encoding()))
6561 return b"".join((self.tag, len_encode(len(v)), v))
6563 def _encode_cer(self, writer):
6564 write_full(writer, self.tag + LENINDEF)
6565 for v in sorted(encode_cer(v) for v in self._values_for_encoding()):
6566 write_full(writer, v)
6567 write_full(writer, EOC)
6569 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
6570 return super(SetOf, self)._decode(
6577 ordering_check=True,
6581 def obj_by_path(pypath): # pragma: no cover
6582 """Import object specified as string Python path
6584 Modules must be separated from classes/functions with ``:``.
6586 >>> obj_by_path("foo.bar:Baz")
6587 <class 'foo.bar.Baz'>
6588 >>> obj_by_path("foo.bar:Baz.boo")
6589 <classmethod 'foo.bar.Baz.boo'>
6591 mod, objs = pypath.rsplit(":", 1)
6592 from importlib import import_module
6593 obj = import_module(mod)
6594 for obj_name in objs.split("."):
6595 obj = getattr(obj, obj_name)
6599 def generic_decoder(): # pragma: no cover
6600 # All of this below is a big hack with self references
6601 choice = PrimitiveTypes()
6602 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6603 choice.specs["SetOf"] = SetOf(schema=choice)
6604 for i in six_xrange(31):
6605 choice.specs["SequenceOf%d" % i] = SequenceOf(
6609 choice.specs["Any"] = Any()
6611 # Class name equals to type name, to omit it from output
6612 class SEQUENCEOF(SequenceOf):
6620 with_decode_path=False,
6621 decode_path_only=(),
6623 def _pprint_pps(pps):
6625 if hasattr(pp, "_fields"):
6627 decode_path_only != () and
6628 pp.decode_path[:len(decode_path_only)] != decode_path_only
6631 if pp.asn1_type_name == Choice.asn1_type_name:
6633 pp_kwargs = pp._asdict()
6634 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6635 pp = _pp(**pp_kwargs)
6636 yield pp_console_row(
6641 with_colours=with_colours,
6642 with_decode_path=with_decode_path,
6643 decode_path_len_decrease=len(decode_path_only),
6645 for row in pp_console_blob(
6647 decode_path_len_decrease=len(decode_path_only),
6651 for row in _pprint_pps(pp):
6653 return "\n".join(_pprint_pps(obj.pps()))
6654 return SEQUENCEOF(), pprint_any
6657 def main(): # pragma: no cover
6659 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6660 parser.add_argument(
6664 help="Skip that number of bytes from the beginning",
6666 parser.add_argument(
6668 help="Python paths to dictionary with OIDs, comma separated",
6670 parser.add_argument(
6672 help="Python path to schema definition to use",
6674 parser.add_argument(
6675 "--defines-by-path",
6676 help="Python path to decoder's defines_by_path",
6678 parser.add_argument(
6680 action="store_true",
6681 help="Disallow BER encoding",
6683 parser.add_argument(
6684 "--print-decode-path",
6685 action="store_true",
6686 help="Print decode paths",
6688 parser.add_argument(
6689 "--decode-path-only",
6690 help="Print only specified decode path",
6692 parser.add_argument(
6694 action="store_true",
6695 help="Allow explicit tag out-of-bound",
6697 parser.add_argument(
6699 type=argparse.FileType("rb"),
6700 help="Path to DER file you want to decode",
6702 args = parser.parse_args()
6703 args.DERFile.seek(args.skip)
6704 der = memoryview(args.DERFile.read())
6705 args.DERFile.close()
6707 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6708 if args.oids else ()
6711 schema = obj_by_path(args.schema)
6712 from functools import partial
6713 pprinter = partial(pprint, big_blobs=True)
6715 schema, pprinter = generic_decoder()
6717 "bered": not args.nobered,
6718 "allow_expl_oob": args.allow_expl_oob,
6720 if args.defines_by_path is not None:
6721 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6722 obj, tail = schema().decode(der, ctx=ctx)
6723 from os import environ
6727 with_colours=environ.get("NO_COLOR") is None,
6728 with_decode_path=args.print_decode_path,
6730 () if args.decode_path_only is None else
6731 tuple(args.decode_path_only.split(":"))
6735 print("\nTrailing data: %s" % hexenc(tail))
6738 if __name__ == "__main__":