3 # cython: language_level=3
4 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
5 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Lesser General Public License as
9 # published by the Free Software Foundation, version 3 of the License.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this program. If not, see <http://www.gnu.org/licenses/>.
18 """Python ASN.1 DER/BER codec with abstract structures
20 This library allows you to marshal various structures in ASN.1 DER
21 format, unmarshal them in BER/CER/DER ones.
25 >>> Integer().decod(raw) == i
28 There are primitive types, holding single values
29 (:py:class:`pyderasn.BitString`,
30 :py:class:`pyderasn.Boolean`,
31 :py:class:`pyderasn.Enumerated`,
32 :py:class:`pyderasn.GeneralizedTime`,
33 :py:class:`pyderasn.Integer`,
34 :py:class:`pyderasn.Null`,
35 :py:class:`pyderasn.ObjectIdentifier`,
36 :py:class:`pyderasn.OctetString`,
37 :py:class:`pyderasn.UTCTime`,
38 :py:class:`various strings <pyderasn.CommonString>`
39 (:py:class:`pyderasn.BMPString`,
40 :py:class:`pyderasn.GeneralString`,
41 :py:class:`pyderasn.GraphicString`,
42 :py:class:`pyderasn.IA5String`,
43 :py:class:`pyderasn.ISO646String`,
44 :py:class:`pyderasn.NumericString`,
45 :py:class:`pyderasn.PrintableString`,
46 :py:class:`pyderasn.T61String`,
47 :py:class:`pyderasn.TeletexString`,
48 :py:class:`pyderasn.UniversalString`,
49 :py:class:`pyderasn.UTF8String`,
50 :py:class:`pyderasn.VideotexString`,
51 :py:class:`pyderasn.VisibleString`)),
52 constructed types, holding multiple primitive types
53 (:py:class:`pyderasn.Sequence`,
54 :py:class:`pyderasn.SequenceOf`,
55 :py:class:`pyderasn.Set`,
56 :py:class:`pyderasn.SetOf`),
57 and special types like
58 :py:class:`pyderasn.Any` and
59 :py:class:`pyderasn.Choice`.
67 Most types in ASN.1 has specific tag for them. ``Obj.tag_default`` is
68 the default tag used during coding process. You can override it with
69 either ``IMPLICIT`` (using either ``impl`` keyword argument or ``impl``
70 class attribute), or ``EXPLICIT`` one (using either ``expl`` keyword
71 argument or ``expl`` class attribute). Both arguments take raw binary
72 string, containing that tag. You can **not** set implicit and explicit
75 There are :py:func:`pyderasn.tag_ctxp` and :py:func:`pyderasn.tag_ctxc`
76 functions, allowing you to easily create ``CONTEXT``
77 ``PRIMITIVE``/``CONSTRUCTED`` tags, by specifying only the required tag
82 EXPLICIT tags always have **constructed** tag. PyDERASN does not
83 explicitly check correctness of schema input here.
87 Implicit tags have **primitive** (``tag_ctxp``) encoding for
92 >>> Integer(impl=tag_ctxp(1))
94 >>> Integer(expl=tag_ctxc(2))
97 Implicit tag is not explicitly shown.
99 Two objects of the same type, but with different implicit/explicit tags
102 You can get object's effective tag (either default or implicited) through
103 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
106 >>> tag_decode(tag_ctxc(123))
108 >>> klass, form, num = tag_decode(tag_ctxc(123))
109 >>> klass == TagClassContext
111 >>> form == TagFormConstructed
114 To determine if object has explicit tag, use ``expled`` boolean property
115 and ``expl_tag`` property, returning explicit tag's value.
120 Many objects in sequences could be ``OPTIONAL`` and could have
121 ``DEFAULT`` value. You can specify that object's property using
122 corresponding keyword arguments.
124 >>> Integer(optional=True, default=123)
125 INTEGER 123 OPTIONAL DEFAULT
127 Those specifications do not play any role in primitive value encoding,
128 but are taken into account when dealing with sequences holding them. For
129 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
132 class Version(Integer):
138 class TBSCertificate(Sequence):
140 ("version", Version(expl=tag_ctxc(0), default="v1")),
143 When default argument is used and value is not specified, then it equals
151 Some objects give ability to set value size constraints. This is either
152 possible integer value, or allowed length of various strings and
153 sequences. Constraints are set in the following way::
158 And values satisfaction is checked as: ``MIN <= X <= MAX``.
160 For simplicity you can also set bounds the following way::
162 bounded_x = X(bounds=(MIN, MAX))
164 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
170 All objects have ``ready`` boolean property, that tells if object is
171 ready to be encoded. If that kind of action is performed on unready
172 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
174 All objects are friendly to ``copy.copy()`` and copied objects can be
177 Also all objects can be safely ``pickle``-d, but pay attention that
178 pickling among different PyDERASN versions is prohibited.
185 Decoding is performed using :py:meth:`pyderasn.Obj.decode` method.
186 ``offset`` optional argument could be used to set initial object's
187 offset in the binary data, for convenience. It returns decoded object
188 and remaining unmarshalled data (tail). Internally all work is done on
189 ``memoryview(data)``, and you can leave returning tail as a memoryview,
190 by specifying ``leavemm=True`` argument.
192 Also note convenient :py:meth:`pyderasn.Obj.decod` method, that
193 immediately checks and raises if there is non-empty tail.
195 When object is decoded, ``decoded`` property is true and you can safely
196 use following properties:
198 * ``offset`` -- position including initial offset where object's tag starts
199 * ``tlen`` -- length of object's tag
200 * ``llen`` -- length of object's length value
201 * ``vlen`` -- length of object's value
202 * ``tlvlen`` -- length of the whole object
204 Pay attention that those values do **not** include anything related to
205 explicit tag. If you want to know information about it, then use:
207 * ``expled`` -- to know if explicit tag is set
208 * ``expl_offset`` (it is lesser than ``offset``)
211 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
212 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
214 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
217 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
224 You can specify so called context keyword argument during
225 :py:meth:`pyderasn.Obj.decode` invocation. It is dictionary containing
226 various options governing decoding process.
228 Currently available context options:
230 * :ref:`allow_default_values <allow_default_values_ctx>`
231 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
232 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
233 * :ref:`bered <bered_ctx>`
234 * :ref:`defines_by_path <defines_by_path_ctx>`
241 All objects have ``pps()`` method, that is a generator of
242 :py:class:`pyderasn.PP` namedtuple, holding various raw information
243 about the object. If ``pps`` is called on sequences, then all underlying
244 ``PP`` will be yielded.
246 You can use :py:func:`pyderasn.pp_console_row` function, converting
247 those ``PP`` to human readable string. Actually exactly it is used for
248 all object ``repr``. But it is easy to write custom formatters.
250 >>> from pyderasn import pprint
251 >>> encoded = Integer(-12345).encode()
252 >>> obj, tail = Integer().decode(encoded)
253 >>> print(pprint(obj))
254 0 [1,1, 2] INTEGER -12345
258 Example certificate::
260 >>> print(pprint(crt))
261 0 [1,3,1604] Certificate SEQUENCE
262 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
263 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
264 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
265 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
266 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
267 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
269 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
270 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
271 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
272 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
273 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
274 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
275 . . . . . . . 13:02:45:53
277 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
278 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
279 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
281 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
282 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
283 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
288 Let's parse that output, human::
290 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
291 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
292 0 1 2 3 4 5 6 7 8 9 10 11
296 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
302 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
308 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
313 Offset of the object, where its DER/BER encoding begins.
314 Pay attention that it does **not** include explicit tag.
316 If explicit tag exists, then this is its length (tag + encoded length).
318 Length of object's tag. For example CHOICE does not have its own tag,
321 Length of encoded length.
323 Length of encoded value.
325 Visual indentation to show the depth of object in the hierarchy.
327 Object's name inside SEQUENCE/CHOICE.
329 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
330 here. "IMPLICIT" is omitted.
332 Object's class name, if set. Omitted if it is just an ordinary simple
333 value (like with ``algorithm`` in example above).
337 Object's value, if set. Can consist of multiple words (like OCTET/BIT
338 STRINGs above). We see ``v3`` value in Version, because it is named.
339 ``rdnSequence`` is the choice of CHOICE type.
341 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
342 default one, specified in the schema.
344 Shows does object contains any kind of BER encoded data (possibly
345 Sequence holding BER-encoded underlying value).
347 Only applicable to BER encoded data. Indefinite length encoding mark.
349 Only applicable to BER encoded data. If object has BER-specific
350 encoding, then ``BER`` will be shown. It does not depend on indefinite
351 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
352 (and its derivatives), ``SET``, ``SET OF``, ``UTCTime``, ``GeneralizedTime``
360 ASN.1 structures often have ANY and OCTET STRING fields, that are
361 DEFINED BY some previously met ObjectIdentifier. This library provides
362 ability to specify mapping between some OID and field that must be
363 decoded with specific specification.
370 :py:class:`pyderasn.ObjectIdentifier` field inside
371 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
372 necessary for decoding structures. For example, CMS (:rfc:`5652`)
375 class ContentInfo(Sequence):
377 ("contentType", ContentType(defines=((("content",), {
378 id_digestedData: DigestedData(),
379 id_signedData: SignedData(),
381 ("content", Any(expl=tag_ctxc(0))),
384 ``contentType`` field tells that it defines that ``content`` must be
385 decoded with ``SignedData`` specification, if ``contentType`` equals to
386 ``id-signedData``. The same applies to ``DigestedData``. If
387 ``contentType`` contains unknown OID, then no automatic decoding is
390 You can specify multiple fields, that will be autodecoded -- that is why
391 ``defines`` kwarg is a sequence. You can specify defined field
392 relatively or absolutely to current decode path. For example ``defines``
393 for AlgorithmIdentifier of X.509's
394 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
398 id_ecPublicKey: ECParameters(),
399 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
401 (("..", "subjectPublicKey"), {
402 id_rsaEncryption: RSAPublicKey(),
403 id_GostR3410_2001: OctetString(),
407 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
408 autodecode its parameters inside SPKI's algorithm and its public key
411 Following types can be automatically decoded (DEFINED BY):
413 * :py:class:`pyderasn.Any`
414 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
415 * :py:class:`pyderasn.OctetString`
416 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
417 ``Any``/``BitString``/``OctetString``-s
419 When any of those fields is automatically decoded, then ``.defined``
420 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
421 was defined, ``value`` contains corresponding decoded value. For example
422 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
424 .. _defines_by_path_ctx:
426 defines_by_path context option
427 ______________________________
429 Sometimes you either can not or do not want to explicitly set *defines*
430 in the schema. You can dynamically apply those definitions when calling
431 ``.decode()`` method.
433 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
434 value must be sequence of following tuples::
436 (decode_path, defines)
438 where ``decode_path`` is a tuple holding so-called decode path to the
439 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
440 ``defines``, holding exactly the same value as accepted in its
441 :ref:`keyword argument <defines>`.
443 For example, again for CMS, you want to automatically decode
444 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
445 structures it may hold. Also, automatically decode ``controlSequence``
448 content_info = ContentInfo().decod(data, ctx={"defines_by_path": (
451 ((("content",), {id_signedData: SignedData()}),),
456 DecodePathDefBy(id_signedData),
461 id_cct_PKIData: PKIData(),
462 id_cct_PKIResponse: PKIResponse(),
468 DecodePathDefBy(id_signedData),
471 DecodePathDefBy(id_cct_PKIResponse),
477 id_cmc_recipientNonce: RecipientNonce(),
478 id_cmc_senderNonce: SenderNonce(),
479 id_cmc_statusInfoV2: CMCStatusInfoV2(),
480 id_cmc_transactionId: TransactionId(),
485 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
486 First function is useful for path construction when some automatic
487 decoding is already done. ``any`` means literally any value it meet --
488 useful for SEQUENCE/SET OF-s.
495 By default PyDERASN accepts only DER encoded data. It always encodes to
496 DER. But you can optionally enable BER decoding with setting ``bered``
497 :ref:`context <ctx>` argument to True. Indefinite lengths and
498 constructed primitive types should be parsed successfully.
500 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
501 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
502 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``,
503 ``UTCTime``, ``GeneralizedTime`` can contain it.
504 * If object has an indefinite length encoding, then its ``lenindef``
505 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
506 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
508 * If object has an indefinite length encoded explicit tag, then
509 ``expl_lenindef`` is set to True.
510 * If object has either any of BER-related encoding (explicit tag
511 indefinite length, object's indefinite length, BER-encoding) or any
512 underlying component has that kind of encoding, then ``bered``
513 attribute is set to True. For example SignedData CMS can have
514 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
515 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
517 EOC (end-of-contents) token's length is taken in advance in object's
520 .. _allow_expl_oob_ctx:
522 Allow explicit tag out-of-bound
523 -------------------------------
525 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
526 one value, more than one object. If you set ``allow_expl_oob`` context
527 option to True, then no error will be raised and that invalid encoding
528 will be silently further processed. But pay attention that offsets and
529 lengths will be invalid in that case.
533 This option should be used only for skipping some decode errors, just
534 to see the decoded structure somehow.
538 .. autoclass:: pyderasn.Obj
546 .. autoclass:: pyderasn.Boolean
551 .. autoclass:: pyderasn.Integer
552 :members: __init__, named
556 .. autoclass:: pyderasn.BitString
557 :members: __init__, bit_len, named
561 .. autoclass:: pyderasn.OctetString
566 .. autoclass:: pyderasn.Null
571 .. autoclass:: pyderasn.ObjectIdentifier
576 .. autoclass:: pyderasn.Enumerated
580 .. autoclass:: pyderasn.CommonString
584 .. autoclass:: pyderasn.NumericString
588 .. autoclass:: pyderasn.PrintableString
589 :members: __init__, allow_asterisk, allow_ampersand
593 .. autoclass:: pyderasn.UTCTime
594 :members: __init__, todatetime
598 .. autoclass:: pyderasn.GeneralizedTime
599 :members: __init__, todatetime
606 .. autoclass:: pyderasn.Choice
607 :members: __init__, choice, value
611 .. autoclass:: PrimitiveTypes
615 .. autoclass:: pyderasn.Any
623 .. autoclass:: pyderasn.Sequence
628 .. autoclass:: pyderasn.Set
633 .. autoclass:: pyderasn.SequenceOf
638 .. autoclass:: pyderasn.SetOf
644 .. autofunction:: pyderasn.abs_decode_path
645 .. autofunction:: pyderasn.colonize_hex
646 .. autofunction:: pyderasn.encode_cer
647 .. autofunction:: pyderasn.file_mmaped
648 .. autofunction:: pyderasn.hexenc
649 .. autofunction:: pyderasn.hexdec
650 .. autofunction:: pyderasn.tag_encode
651 .. autofunction:: pyderasn.tag_decode
652 .. autofunction:: pyderasn.tag_ctxp
653 .. autofunction:: pyderasn.tag_ctxc
654 .. autoclass:: pyderasn.DecodeError
656 .. autoclass:: pyderasn.NotEnoughData
657 .. autoclass:: pyderasn.ExceedingData
658 .. autoclass:: pyderasn.LenIndefForm
659 .. autoclass:: pyderasn.TagMismatch
660 .. autoclass:: pyderasn.InvalidLength
661 .. autoclass:: pyderasn.InvalidOID
662 .. autoclass:: pyderasn.ObjUnknown
663 .. autoclass:: pyderasn.ObjNotReady
664 .. autoclass:: pyderasn.InvalidValueType
665 .. autoclass:: pyderasn.BoundsError
672 You can decode DER/BER files using command line abilities::
674 $ python -m pyderasn --schema tests.test_crts:Certificate path/to/file
676 If there is no schema for your file, then you can try parsing it without,
677 but of course IMPLICIT tags will often make it impossible. But result is
678 good enough for the certificate above::
680 $ python -m pyderasn path/to/file
681 0 [1,3,1604] . >: SEQUENCE OF
682 4 [1,3,1453] . . >: SEQUENCE OF
683 8 [0,0, 5] . . . . >: [0] ANY
684 . . . . . A0:03:02:01:02
685 13 [1,1, 3] . . . . >: INTEGER 61595
686 18 [1,1, 13] . . . . >: SEQUENCE OF
687 20 [1,1, 9] . . . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
688 31 [1,1, 0] . . . . . . >: NULL
689 33 [1,3, 274] . . . . >: SEQUENCE OF
690 37 [1,1, 11] . . . . . . >: SET OF
691 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
692 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER 2.5.4.6
693 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
695 1409 [1,1, 50] . . . . . . >: SEQUENCE OF
696 1411 [1,1, 8] . . . . . . . . >: OBJECT IDENTIFIER 1.3.6.1.5.5.7.1.1
697 1421 [1,1, 38] . . . . . . . . >: OCTET STRING 38 bytes
698 . . . . . . . . . 30:24:30:22:06:08:2B:06:01:05:05:07:30:01:86:16
699 . . . . . . . . . 68:74:74:70:3A:2F:2F:6F:63:73:70:2E:69:70:73:63
700 . . . . . . . . . 61:2E:63:6F:6D:2F
701 1461 [1,1, 13] . . >: SEQUENCE OF
702 1463 [1,1, 9] . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
703 1474 [1,1, 0] . . . . >: NULL
704 1476 [1,2, 129] . . >: BIT STRING 1024 bits
705 . . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
706 . . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
712 If you have got dictionaries with ObjectIdentifiers, like example one
713 from ``tests/test_crts.py``::
716 "1.2.840.113549.1.1.1": "id-rsaEncryption",
717 "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
719 "2.5.4.10": "id-at-organizationName",
720 "2.5.4.11": "id-at-organizationalUnitName",
723 then you can pass it to pretty printer to see human readable OIDs::
725 $ python -m pyderasn --oids tests.test_crts:stroid2name path/to/file
727 37 [1,1, 11] . . . . . . >: SET OF
728 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
729 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
730 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
731 50 [1,1, 18] . . . . . . >: SET OF
732 52 [1,1, 16] . . . . . . . . >: SEQUENCE OF
733 54 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
734 59 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
735 70 [1,1, 18] . . . . . . >: SET OF
736 72 [1,1, 16] . . . . . . . . >: SEQUENCE OF
737 74 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
738 79 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
744 Each decoded element has so-called decode path: sequence of structure
745 names it is passing during the decode process. Each element has its own
746 unique path inside the whole ASN.1 tree. You can print it out with
747 ``--print-decode-path`` option::
749 $ python -m pyderasn --schema path.to:Certificate --print-decode-path path/to/file
750 0 [1,3,1604] Certificate SEQUENCE []
751 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE [tbsCertificate]
752 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL [tbsCertificate:version]
753 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595 [tbsCertificate:serialNumber]
754 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE [tbsCertificate:signature]
755 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5 [tbsCertificate:signature:algorithm]
756 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL [tbsCertificate:signature:parameters]
758 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence [tbsCertificate:issuer]
759 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF [tbsCertificate:issuer:rdnSequence]
760 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF [tbsCertificate:issuer:rdnSequence:0]
761 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE [tbsCertificate:issuer:rdnSequence:0:0]
762 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6 [tbsCertificate:issuer:rdnSequence:0:0:type]
763 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY [tbsCertificate:issuer:rdnSequence:0:0:value]
764 . . . . . . . 13:02:45:53
765 46 [1,1, 2] . . . . . . . DEFINED BY 2.5.4.6: CountryName PrintableString ES [tbsCertificate:issuer:rdnSequence:0:0:value:DEFINED BY 2.5.4.6]
768 Now you can print only the specified tree, for example signature algorithm::
770 $ python -m pyderasn --schema path.to:Certificate --decode-path-only tbsCertificate:signature path/to/file
771 18 [1,1, 13] AlgorithmIdentifier SEQUENCE
772 20 [1,1, 9] . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
773 31 [0,0, 2] . parameters: [UNIV 5] ANY OPTIONAL
777 from codecs import getdecoder
778 from codecs import getencoder
779 from collections import namedtuple
780 from collections import OrderedDict
781 from copy import copy
782 from datetime import datetime
783 from datetime import timedelta
784 from io import BytesIO
785 from math import ceil
786 from mmap import mmap
787 from mmap import PROT_READ
788 from operator import attrgetter
789 from string import ascii_letters
790 from string import digits
791 from sys import version_info
792 from unicodedata import category as unicat
794 from six import add_metaclass
795 from six import binary_type
796 from six import byte2int
797 from six import indexbytes
798 from six import int2byte
799 from six import integer_types
800 from six import iterbytes
801 from six import iteritems
802 from six import itervalues
804 from six import string_types
805 from six import text_type
806 from six import unichr as six_unichr
807 from six.moves import xrange as six_xrange
811 from termcolor import colored
812 except ImportError: # pragma: no cover
813 def colored(what, *args, **kwargs):
861 "TagClassApplication",
865 "TagFormConstructed",
876 TagClassUniversal = 0
877 TagClassApplication = 1 << 6
878 TagClassContext = 1 << 7
879 TagClassPrivate = 1 << 6 | 1 << 7
881 TagFormConstructed = 1 << 5
884 TagClassApplication: "APPLICATION ",
885 TagClassPrivate: "PRIVATE ",
886 TagClassUniversal: "UNIV ",
890 LENINDEF = b"\x80" # length indefinite mark
891 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
892 NAMEDTUPLE_KWARGS = {} if version_info < (3, 6) else {"module": __name__}
893 SET01 = frozenset("01")
894 DECIMALS = frozenset(digits)
899 """Make mmap-ed memoryview for reading from file
901 :param fd: file object
902 :returns: memoryview over read-only mmap-ing of the whole file
904 return memoryview(mmap(fd.fileno(), 0, prot=PROT_READ))
907 if not set(value) <= DECIMALS:
908 raise ValueError("non-pure integer")
911 def fractions2float(fractions_raw):
912 pureint(fractions_raw)
913 return float("0." + fractions_raw)
916 def get_def_by_path(defines_by_path, sub_decode_path):
917 """Get define by decode path
919 for path, define in defines_by_path:
920 if len(path) != len(sub_decode_path):
922 for p1, p2 in zip(path, sub_decode_path):
923 if (not p1 is any) and (p1 != p2):
929 ########################################################################
931 ########################################################################
933 class ASN1Error(ValueError):
937 class DecodeError(ASN1Error):
938 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
940 :param str msg: reason of decode failing
941 :param klass: optional exact DecodeError inherited class (like
942 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
943 :py:exc:`InvalidLength`)
944 :param decode_path: tuple of strings. It contains human
945 readable names of the fields through which
946 decoding process has passed
947 :param int offset: binary offset where failure happened
949 super(DecodeError, self).__init__()
952 self.decode_path = decode_path
958 "" if self.klass is None else self.klass.__name__,
960 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
961 if len(self.decode_path) > 0 else ""
963 ("(at %d)" % self.offset) if self.offset > 0 else "",
969 return "%s(%s)" % (self.__class__.__name__, self)
972 class NotEnoughData(DecodeError):
976 class ExceedingData(ASN1Error):
977 def __init__(self, nbytes):
978 super(ExceedingData, self).__init__()
982 return "%d trailing bytes" % self.nbytes
985 return "%s(%s)" % (self.__class__.__name__, self)
988 class LenIndefForm(DecodeError):
992 class TagMismatch(DecodeError):
996 class InvalidLength(DecodeError):
1000 class InvalidOID(DecodeError):
1004 class ObjUnknown(ASN1Error):
1005 def __init__(self, name):
1006 super(ObjUnknown, self).__init__()
1010 return "object is unknown: %s" % self.name
1013 return "%s(%s)" % (self.__class__.__name__, self)
1016 class ObjNotReady(ASN1Error):
1017 def __init__(self, name):
1018 super(ObjNotReady, self).__init__()
1022 return "object is not ready: %s" % self.name
1025 return "%s(%s)" % (self.__class__.__name__, self)
1028 class InvalidValueType(ASN1Error):
1029 def __init__(self, expected_types):
1030 super(InvalidValueType, self).__init__()
1031 self.expected_types = expected_types
1034 return "invalid value type, expected: %s" % ", ".join(
1035 [repr(t) for t in self.expected_types]
1039 return "%s(%s)" % (self.__class__.__name__, self)
1042 class BoundsError(ASN1Error):
1043 def __init__(self, bound_min, value, bound_max):
1044 super(BoundsError, self).__init__()
1045 self.bound_min = bound_min
1047 self.bound_max = bound_max
1050 return "unsatisfied bounds: %s <= %s <= %s" % (
1057 return "%s(%s)" % (self.__class__.__name__, self)
1060 ########################################################################
1062 ########################################################################
1064 _hexdecoder = getdecoder("hex")
1065 _hexencoder = getencoder("hex")
1069 """Binary data to hexadecimal string convert
1071 return _hexdecoder(data)[0]
1075 """Hexadecimal string to binary data convert
1077 return _hexencoder(data)[0].decode("ascii")
1080 def int_bytes_len(num, byte_len=8):
1083 return int(ceil(float(num.bit_length()) / byte_len))
1086 def zero_ended_encode(num):
1087 octets = bytearray(int_bytes_len(num, 7))
1089 octets[i] = num & 0x7F
1093 octets[i] = 0x80 | (num & 0x7F)
1096 return bytes(octets)
1099 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
1100 """Encode tag to binary form
1102 :param int num: tag's number
1103 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
1104 :py:data:`pyderasn.TagClassContext`,
1105 :py:data:`pyderasn.TagClassApplication`,
1106 :py:data:`pyderasn.TagClassPrivate`)
1107 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
1108 :py:data:`pyderasn.TagFormConstructed`)
1112 return int2byte(klass | form | num)
1113 # [XX|X|11111][1.......][1.......] ... [0.......]
1114 return int2byte(klass | form | 31) + zero_ended_encode(num)
1117 def tag_decode(tag):
1118 """Decode tag from binary form
1122 No validation is performed, assuming that it has already passed.
1124 It returns tuple with three integers, as
1125 :py:func:`pyderasn.tag_encode` accepts.
1127 first_octet = byte2int(tag)
1128 klass = first_octet & 0xC0
1129 form = first_octet & 0x20
1130 if first_octet & 0x1F < 0x1F:
1131 return (klass, form, first_octet & 0x1F)
1133 for octet in iterbytes(tag[1:]):
1136 return (klass, form, num)
1140 """Create CONTEXT PRIMITIVE tag
1142 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
1146 """Create CONTEXT CONSTRUCTED tag
1148 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
1151 def tag_strip(data):
1152 """Take off tag from the data
1154 :returns: (encoded tag, tag length, remaining data)
1157 raise NotEnoughData("no data at all")
1158 if byte2int(data) & 0x1F < 31:
1159 return data[:1], 1, data[1:]
1164 raise DecodeError("unfinished tag")
1165 if indexbytes(data, i) & 0x80 == 0:
1168 return data[:i], i, data[i:]
1174 octets = bytearray(int_bytes_len(l) + 1)
1175 octets[0] = 0x80 | (len(octets) - 1)
1176 for i in six_xrange(len(octets) - 1, 0, -1):
1177 octets[i] = l & 0xFF
1179 return bytes(octets)
1182 def len_decode(data):
1185 :returns: (decoded length, length's length, remaining data)
1186 :raises LenIndefForm: if indefinite form encoding is met
1189 raise NotEnoughData("no data at all")
1190 first_octet = byte2int(data)
1191 if first_octet & 0x80 == 0:
1192 return first_octet, 1, data[1:]
1193 octets_num = first_octet & 0x7F
1194 if octets_num + 1 > len(data):
1195 raise NotEnoughData("encoded length is longer than data")
1197 raise LenIndefForm()
1198 if byte2int(data[1:]) == 0:
1199 raise DecodeError("leading zeros")
1201 for v in iterbytes(data[1:1 + octets_num]):
1204 raise DecodeError("long form instead of short one")
1205 return l, 1 + octets_num, data[1 + octets_num:]
1208 LEN1K = len_encode(1000)
1211 def write_full(writer, data):
1212 """Fully write provided data
1214 BytesIO does not guarantee that the whole data will be written at once.
1216 data = memoryview(data)
1218 while written != len(data):
1219 n = writer(data[written:])
1221 raise ValueError("can not write to buf")
1225 ########################################################################
1227 ########################################################################
1229 class AutoAddSlots(type):
1230 def __new__(cls, name, bases, _dict):
1231 _dict["__slots__"] = _dict.get("__slots__", ())
1232 return type.__new__(cls, name, bases, _dict)
1235 BasicState = namedtuple("BasicState", (
1248 ), **NAMEDTUPLE_KWARGS)
1251 @add_metaclass(AutoAddSlots)
1253 """Common ASN.1 object class
1255 All ASN.1 types are inherited from it. It has metaclass that
1256 automatically adds ``__slots__`` to all inherited classes.
1281 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1282 self._expl = getattr(self, "expl", None) if expl is None else expl
1283 if self.tag != self.tag_default and self._expl is not None:
1284 raise ValueError("implicit and explicit tags can not be set simultaneously")
1285 if self.tag is None:
1286 self._tag_order = None
1288 tag_class, _, tag_num = tag_decode(
1289 self.tag if self._expl is None else self._expl
1291 self._tag_order = (tag_class, tag_num)
1292 if default is not None:
1294 self.optional = optional
1295 self.offset, self.llen, self.vlen = _decoded
1297 self.expl_lenindef = False
1298 self.lenindef = False
1299 self.ber_encoded = False
1302 def ready(self): # pragma: no cover
1303 """Is object ready to be encoded?
1305 raise NotImplementedError()
1307 def _assert_ready(self):
1309 raise ObjNotReady(self.__class__.__name__)
1313 """Is either object or any elements inside is BER encoded?
1315 return self.expl_lenindef or self.lenindef or self.ber_encoded
1319 """Is object decoded?
1321 return (self.llen + self.vlen) > 0
1323 def __getstate__(self): # pragma: no cover
1324 """Used for making safe to be mutable pickleable copies
1326 raise NotImplementedError()
1328 def __setstate__(self, state):
1329 if state.version != __version__:
1330 raise ValueError("data is pickled by different PyDERASN version")
1331 self.tag = state.tag
1332 self._tag_order = state.tag_order
1333 self._expl = state.expl
1334 self.default = state.default
1335 self.optional = state.optional
1336 self.offset = state.offset
1337 self.llen = state.llen
1338 self.vlen = state.vlen
1339 self.expl_lenindef = state.expl_lenindef
1340 self.lenindef = state.lenindef
1341 self.ber_encoded = state.ber_encoded
1344 def tag_order(self):
1345 """Tag's (class, number) used for DER/CER sorting
1347 return self._tag_order
1350 def tag_order_cer(self):
1351 return self.tag_order
1355 """See :ref:`decoding`
1357 return len(self.tag)
1361 """See :ref:`decoding`
1363 return self.tlen + self.llen + self.vlen
1365 def __str__(self): # pragma: no cover
1366 return self.__bytes__() if PY2 else self.__unicode__()
1368 def __ne__(self, their):
1369 return not(self == their)
1371 def __gt__(self, their): # pragma: no cover
1372 return not(self < their)
1374 def __le__(self, their): # pragma: no cover
1375 return (self == their) or (self < their)
1377 def __ge__(self, their): # pragma: no cover
1378 return (self == their) or (self > their)
1380 def _encode(self): # pragma: no cover
1381 raise NotImplementedError()
1383 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode): # pragma: no cover
1384 yield NotImplemented
1387 """Encode the structure
1389 :returns: DER representation
1391 raw = self._encode()
1392 if self._expl is None:
1394 return b"".join((self._expl, len_encode(len(raw)), raw))
1396 def encode_cer(self, writer):
1397 if self._expl is not None:
1398 write_full(writer, self._expl + LENINDEF)
1399 if getattr(self, "der_forced", False):
1400 write_full(writer, self._encode())
1402 self._encode_cer(writer)
1403 if self._expl is not None:
1404 write_full(writer, EOC)
1406 def _encode_cer(self, writer):
1407 write_full(writer, self._encode())
1409 def hexencode(self):
1410 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1412 return hexenc(self.encode())
1422 _ctx_immutable=True,
1424 result = next(self.decode_evgen(
1436 _, obj, tail = result
1447 _ctx_immutable=True,
1452 :param data: either binary or memoryview
1453 :param int offset: initial data's offset
1454 :param bool leavemm: do we need to leave memoryview of remaining
1455 data as is, or convert it to bytes otherwise
1456 :param ctx: optional :ref:`context <ctx>` governing decoding process
1457 :param tag_only: decode only the tag, without length and contents
1458 (used only in Choice and Set structures, trying to
1459 determine if tag satisfies the schema)
1460 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1462 :returns: (Obj, remaining data)
1464 .. seealso:: :ref:`decoding`
1468 elif _ctx_immutable:
1470 tlv = memoryview(data)
1473 get_def_by_path(ctx.get("evgen_mode_upto", ()), decode_path) is not None
1476 if self._expl is None:
1477 for result in self._decode(
1480 decode_path=decode_path,
1483 evgen_mode=_evgen_mode,
1488 _decode_path, obj, tail = result
1489 if not _decode_path is decode_path:
1493 t, tlen, lv = tag_strip(tlv)
1494 except DecodeError as err:
1495 raise err.__class__(
1497 klass=self.__class__,
1498 decode_path=decode_path,
1503 klass=self.__class__,
1504 decode_path=decode_path,
1508 l, llen, v = len_decode(lv)
1509 except LenIndefForm as err:
1510 if not ctx.get("bered", False):
1511 raise err.__class__(
1513 klass=self.__class__,
1514 decode_path=decode_path,
1518 offset += tlen + llen
1519 for result in self._decode(
1522 decode_path=decode_path,
1525 evgen_mode=_evgen_mode,
1527 if tag_only: # pragma: no cover
1530 _decode_path, obj, tail = result
1531 if not _decode_path is decode_path:
1533 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1534 if eoc_expected.tobytes() != EOC:
1537 klass=self.__class__,
1538 decode_path=decode_path,
1542 obj.expl_lenindef = True
1543 except DecodeError as err:
1544 raise err.__class__(
1546 klass=self.__class__,
1547 decode_path=decode_path,
1552 raise NotEnoughData(
1553 "encoded length is longer than data",
1554 klass=self.__class__,
1555 decode_path=decode_path,
1558 for result in self._decode(
1560 offset=offset + tlen + llen,
1561 decode_path=decode_path,
1564 evgen_mode=_evgen_mode,
1566 if tag_only: # pragma: no cover
1569 _decode_path, obj, tail = result
1570 if not _decode_path is decode_path:
1572 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1574 "explicit tag out-of-bound, longer than data",
1575 klass=self.__class__,
1576 decode_path=decode_path,
1579 yield decode_path, obj, (tail if leavemm else tail.tobytes())
1581 def decod(self, data, offset=0, decode_path=(), ctx=None):
1582 """Decode the data, check that tail is empty
1584 :raises ExceedingData: if tail is not empty
1586 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1587 (decode without tail) that also checks that there is no
1590 obj, tail = self.decode(
1593 decode_path=decode_path,
1598 raise ExceedingData(len(tail))
1601 def hexdecode(self, data, *args, **kwargs):
1602 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1604 return self.decode(hexdec(data), *args, **kwargs)
1606 def hexdecod(self, data, *args, **kwargs):
1607 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1609 return self.decod(hexdec(data), *args, **kwargs)
1613 """See :ref:`decoding`
1615 return self._expl is not None
1619 """See :ref:`decoding`
1624 def expl_tlen(self):
1625 """See :ref:`decoding`
1627 return len(self._expl)
1630 def expl_llen(self):
1631 """See :ref:`decoding`
1633 if self.expl_lenindef:
1635 return len(len_encode(self.tlvlen))
1638 def expl_offset(self):
1639 """See :ref:`decoding`
1641 return self.offset - self.expl_tlen - self.expl_llen
1644 def expl_vlen(self):
1645 """See :ref:`decoding`
1650 def expl_tlvlen(self):
1651 """See :ref:`decoding`
1653 return self.expl_tlen + self.expl_llen + self.expl_vlen
1656 def fulloffset(self):
1657 """See :ref:`decoding`
1659 return self.expl_offset if self.expled else self.offset
1663 """See :ref:`decoding`
1665 return self.expl_tlvlen if self.expled else self.tlvlen
1667 def pps_lenindef(self, decode_path):
1668 if self.lenindef and not (
1669 getattr(self, "defined", None) is not None and
1670 self.defined[1].lenindef
1673 asn1_type_name="EOC",
1675 decode_path=decode_path,
1677 self.offset + self.tlvlen -
1678 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1686 if self.expl_lenindef:
1688 asn1_type_name="EOC",
1689 obj_name="EXPLICIT",
1690 decode_path=decode_path,
1691 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1700 def encode_cer(obj):
1701 """Encode to CER in memory
1704 obj.encode_cer(buf.write)
1705 return buf.getvalue()
1708 class DecodePathDefBy(object):
1709 """DEFINED BY representation inside decode path
1711 __slots__ = ("defined_by",)
1713 def __init__(self, defined_by):
1714 self.defined_by = defined_by
1716 def __ne__(self, their):
1717 return not(self == their)
1719 def __eq__(self, their):
1720 if not isinstance(their, self.__class__):
1722 return self.defined_by == their.defined_by
1725 return "DEFINED BY " + str(self.defined_by)
1728 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1731 ########################################################################
1733 ########################################################################
1735 PP = namedtuple("PP", (
1758 ), **NAMEDTUPLE_KWARGS)
1763 asn1_type_name="unknown",
1780 expl_lenindef=False,
1811 def _colourize(what, colour, with_colours, attrs=("bold",)):
1812 return colored(what, colour, attrs=attrs) if with_colours else what
1815 def colonize_hex(hexed):
1816 """Separate hexadecimal string with colons
1818 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1827 with_decode_path=False,
1828 decode_path_len_decrease=0,
1835 " " if pp.expl_offset is None else
1836 ("-%d" % (pp.offset - pp.expl_offset))
1838 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1840 col = _colourize(col, "red", with_colours, ())
1841 col += _colourize("B", "red", with_colours) if pp.bered else " "
1843 col = "[%d,%d,%4d]%s" % (
1847 LENINDEF_PP_CHAR if pp.lenindef else " "
1849 col = _colourize(col, "green", with_colours, ())
1851 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1852 if decode_path_len > 0:
1853 cols.append(" ." * decode_path_len)
1854 ent = pp.decode_path[-1]
1855 if isinstance(ent, DecodePathDefBy):
1856 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1857 value = str(ent.defined_by)
1860 len(oid_maps) > 0 and
1861 ent.defined_by.asn1_type_name ==
1862 ObjectIdentifier.asn1_type_name
1864 for oid_map in oid_maps:
1865 oid_name = oid_map.get(value)
1866 if oid_name is not None:
1867 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1869 if oid_name is None:
1870 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1872 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1873 if pp.expl is not None:
1874 klass, _, num = pp.expl
1875 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1876 cols.append(_colourize(col, "blue", with_colours))
1877 if pp.impl is not None:
1878 klass, _, num = pp.impl
1879 col = "[%s%d]" % (TagClassReprs[klass], num)
1880 cols.append(_colourize(col, "blue", with_colours))
1881 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1882 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1884 cols.append(_colourize("BER", "red", with_colours))
1885 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1886 if pp.value is not None:
1888 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1890 len(oid_maps) > 0 and
1891 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1893 for oid_map in oid_maps:
1894 oid_name = oid_map.get(value)
1895 if oid_name is not None:
1896 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1898 if pp.asn1_type_name == Integer.asn1_type_name:
1899 hex_repr = hex(int(pp.obj._value))[2:].upper()
1900 if len(hex_repr) % 2 != 0:
1901 hex_repr = "0" + hex_repr
1902 cols.append(_colourize(
1903 "(%s)" % colonize_hex(hex_repr),
1908 if pp.blob.__class__ == binary_type:
1909 cols.append(hexenc(pp.blob))
1910 elif pp.blob.__class__ == tuple:
1911 cols.append(", ".join(pp.blob))
1913 cols.append(_colourize("OPTIONAL", "red", with_colours))
1915 cols.append(_colourize("DEFAULT", "red", with_colours))
1916 if with_decode_path:
1917 cols.append(_colourize(
1918 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1922 return " ".join(cols)
1925 def pp_console_blob(pp, decode_path_len_decrease=0):
1926 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1927 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1928 if decode_path_len > 0:
1929 cols.append(" ." * (decode_path_len + 1))
1930 if pp.blob.__class__ == binary_type:
1931 blob = hexenc(pp.blob).upper()
1932 for i in six_xrange(0, len(blob), 32):
1933 chunk = blob[i:i + 32]
1934 yield " ".join(cols + [colonize_hex(chunk)])
1935 elif pp.blob.__class__ == tuple:
1936 yield " ".join(cols + [", ".join(pp.blob)])
1944 with_decode_path=False,
1945 decode_path_only=(),
1947 """Pretty print object
1949 :param Obj obj: object you want to pretty print
1950 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1951 Its human readable form is printed when OID is met
1952 :param big_blobs: if large binary objects are met (like OctetString
1953 values), do we need to print them too, on separate
1955 :param with_colours: colourize output, if ``termcolor`` library
1957 :param with_decode_path: print decode path
1958 :param decode_path_only: print only that specified decode path
1960 def _pprint_pps(pps):
1962 if hasattr(pp, "_fields"):
1964 decode_path_only != () and
1966 str(p) for p in pp.decode_path[:len(decode_path_only)]
1967 ) != decode_path_only
1971 yield pp_console_row(
1976 with_colours=with_colours,
1977 with_decode_path=with_decode_path,
1978 decode_path_len_decrease=len(decode_path_only),
1980 for row in pp_console_blob(
1982 decode_path_len_decrease=len(decode_path_only),
1986 yield pp_console_row(
1991 with_colours=with_colours,
1992 with_decode_path=with_decode_path,
1993 decode_path_len_decrease=len(decode_path_only),
1996 for row in _pprint_pps(pp):
1998 return "\n".join(_pprint_pps(obj.pps()))
2001 ########################################################################
2002 # ASN.1 primitive types
2003 ########################################################################
2005 BooleanState = namedtuple(
2007 BasicState._fields + ("value",),
2013 """``BOOLEAN`` boolean type
2015 >>> b = Boolean(True)
2017 >>> b == Boolean(True)
2023 tag_default = tag_encode(1)
2024 asn1_type_name = "BOOLEAN"
2036 :param value: set the value. Either boolean type, or
2037 :py:class:`pyderasn.Boolean` object
2038 :param bytes impl: override default tag with ``IMPLICIT`` one
2039 :param bytes expl: override default tag with ``EXPLICIT`` one
2040 :param default: set default value. Type same as in ``value``
2041 :param bool optional: is object ``OPTIONAL`` in sequence
2043 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
2044 self._value = None if value is None else self._value_sanitize(value)
2045 if default is not None:
2046 default = self._value_sanitize(default)
2047 self.default = self.__class__(
2053 self._value = default
2055 def _value_sanitize(self, value):
2056 if value.__class__ == bool:
2058 if issubclass(value.__class__, Boolean):
2060 raise InvalidValueType((self.__class__, bool))
2064 return self._value is not None
2066 def __getstate__(self):
2067 return BooleanState(
2083 def __setstate__(self, state):
2084 super(Boolean, self).__setstate__(state)
2085 self._value = state.value
2087 def __nonzero__(self):
2088 self._assert_ready()
2092 self._assert_ready()
2095 def __eq__(self, their):
2096 if their.__class__ == bool:
2097 return self._value == their
2098 if not issubclass(their.__class__, Boolean):
2101 self._value == their._value and
2102 self.tag == their.tag and
2103 self._expl == their._expl
2114 return self.__class__(
2116 impl=self.tag if impl is None else impl,
2117 expl=self._expl if expl is None else expl,
2118 default=self.default if default is None else default,
2119 optional=self.optional if optional is None else optional,
2123 self._assert_ready()
2127 (b"\xFF" if self._value else b"\x00"),
2130 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2132 t, _, lv = tag_strip(tlv)
2133 except DecodeError as err:
2134 raise err.__class__(
2136 klass=self.__class__,
2137 decode_path=decode_path,
2142 klass=self.__class__,
2143 decode_path=decode_path,
2150 l, _, v = len_decode(lv)
2151 except DecodeError as err:
2152 raise err.__class__(
2154 klass=self.__class__,
2155 decode_path=decode_path,
2159 raise InvalidLength(
2160 "Boolean's length must be equal to 1",
2161 klass=self.__class__,
2162 decode_path=decode_path,
2166 raise NotEnoughData(
2167 "encoded length is longer than data",
2168 klass=self.__class__,
2169 decode_path=decode_path,
2172 first_octet = byte2int(v)
2174 if first_octet == 0:
2176 elif first_octet == 0xFF:
2178 elif ctx.get("bered", False):
2183 "unacceptable Boolean value",
2184 klass=self.__class__,
2185 decode_path=decode_path,
2188 obj = self.__class__(
2192 default=self.default,
2193 optional=self.optional,
2194 _decoded=(offset, 1, 1),
2196 obj.ber_encoded = ber_encoded
2197 yield decode_path, obj, v[1:]
2200 return pp_console_row(next(self.pps()))
2202 def pps(self, decode_path=()):
2205 asn1_type_name=self.asn1_type_name,
2206 obj_name=self.__class__.__name__,
2207 decode_path=decode_path,
2208 value=str(self._value) if self.ready else None,
2209 optional=self.optional,
2210 default=self == self.default,
2211 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2212 expl=None if self._expl is None else tag_decode(self._expl),
2217 expl_offset=self.expl_offset if self.expled else None,
2218 expl_tlen=self.expl_tlen if self.expled else None,
2219 expl_llen=self.expl_llen if self.expled else None,
2220 expl_vlen=self.expl_vlen if self.expled else None,
2221 expl_lenindef=self.expl_lenindef,
2222 ber_encoded=self.ber_encoded,
2225 for pp in self.pps_lenindef(decode_path):
2229 IntegerState = namedtuple(
2231 BasicState._fields + ("specs", "value", "bound_min", "bound_max"),
2237 """``INTEGER`` integer type
2239 >>> b = Integer(-123)
2241 >>> b == Integer(-123)
2246 >>> Integer(2, bounds=(1, 3))
2248 >>> Integer(5, bounds=(1, 3))
2249 Traceback (most recent call last):
2250 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2254 class Version(Integer):
2261 >>> v = Version("v1")
2268 {'v3': 2, 'v1': 0, 'v2': 1}
2270 __slots__ = ("specs", "_bound_min", "_bound_max")
2271 tag_default = tag_encode(2)
2272 asn1_type_name = "INTEGER"
2286 :param value: set the value. Either integer type, named value
2287 (if ``schema`` is specified in the class), or
2288 :py:class:`pyderasn.Integer` object
2289 :param bounds: set ``(MIN, MAX)`` value constraint.
2290 (-inf, +inf) by default
2291 :param bytes impl: override default tag with ``IMPLICIT`` one
2292 :param bytes expl: override default tag with ``EXPLICIT`` one
2293 :param default: set default value. Type same as in ``value``
2294 :param bool optional: is object ``OPTIONAL`` in sequence
2296 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2298 specs = getattr(self, "schema", {}) if _specs is None else _specs
2299 self.specs = specs if specs.__class__ == dict else dict(specs)
2300 self._bound_min, self._bound_max = getattr(
2303 (float("-inf"), float("+inf")),
2304 ) if bounds is None else bounds
2305 if value is not None:
2306 self._value = self._value_sanitize(value)
2307 if default is not None:
2308 default = self._value_sanitize(default)
2309 self.default = self.__class__(
2315 if self._value is None:
2316 self._value = default
2318 def _value_sanitize(self, value):
2319 if isinstance(value, integer_types):
2321 elif issubclass(value.__class__, Integer):
2322 value = value._value
2323 elif value.__class__ == str:
2324 value = self.specs.get(value)
2326 raise ObjUnknown("integer value: %s" % value)
2328 raise InvalidValueType((self.__class__, int, str))
2329 if not self._bound_min <= value <= self._bound_max:
2330 raise BoundsError(self._bound_min, value, self._bound_max)
2335 return self._value is not None
2337 def __getstate__(self):
2338 return IntegerState(
2357 def __setstate__(self, state):
2358 super(Integer, self).__setstate__(state)
2359 self.specs = state.specs
2360 self._value = state.value
2361 self._bound_min = state.bound_min
2362 self._bound_max = state.bound_max
2365 self._assert_ready()
2366 return int(self._value)
2369 self._assert_ready()
2372 bytes(self._expl or b"") +
2373 str(self._value).encode("ascii"),
2376 def __eq__(self, their):
2377 if isinstance(their, integer_types):
2378 return self._value == their
2379 if not issubclass(their.__class__, Integer):
2382 self._value == their._value and
2383 self.tag == their.tag and
2384 self._expl == their._expl
2387 def __lt__(self, their):
2388 return self._value < their._value
2392 """Return named representation (if exists) of the value
2394 for name, value in iteritems(self.specs):
2395 if value == self._value:
2408 return self.__class__(
2411 (self._bound_min, self._bound_max)
2412 if bounds is None else bounds
2414 impl=self.tag if impl is None else impl,
2415 expl=self._expl if expl is None else expl,
2416 default=self.default if default is None else default,
2417 optional=self.optional if optional is None else optional,
2422 self._assert_ready()
2426 octets = bytearray([0])
2430 octets = bytearray()
2432 octets.append((value & 0xFF) ^ 0xFF)
2434 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2437 octets = bytearray()
2439 octets.append(value & 0xFF)
2441 if octets[-1] & 0x80 > 0:
2444 octets = bytes(octets)
2446 bytes_len = ceil(value.bit_length() / 8) or 1
2449 octets = value.to_bytes(
2454 except OverflowError:
2458 return b"".join((self.tag, len_encode(len(octets)), octets))
2460 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2462 t, _, lv = tag_strip(tlv)
2463 except DecodeError as err:
2464 raise err.__class__(
2466 klass=self.__class__,
2467 decode_path=decode_path,
2472 klass=self.__class__,
2473 decode_path=decode_path,
2480 l, llen, v = len_decode(lv)
2481 except DecodeError as err:
2482 raise err.__class__(
2484 klass=self.__class__,
2485 decode_path=decode_path,
2489 raise NotEnoughData(
2490 "encoded length is longer than data",
2491 klass=self.__class__,
2492 decode_path=decode_path,
2496 raise NotEnoughData(
2498 klass=self.__class__,
2499 decode_path=decode_path,
2502 v, tail = v[:l], v[l:]
2503 first_octet = byte2int(v)
2505 second_octet = byte2int(v[1:])
2507 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2508 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2511 "non normalized integer",
2512 klass=self.__class__,
2513 decode_path=decode_path,
2518 if first_octet & 0x80 > 0:
2519 octets = bytearray()
2520 for octet in bytearray(v):
2521 octets.append(octet ^ 0xFF)
2522 for octet in octets:
2523 value = (value << 8) | octet
2527 for octet in bytearray(v):
2528 value = (value << 8) | octet
2530 value = int.from_bytes(v, byteorder="big", signed=True)
2532 obj = self.__class__(
2534 bounds=(self._bound_min, self._bound_max),
2537 default=self.default,
2538 optional=self.optional,
2540 _decoded=(offset, llen, l),
2542 except BoundsError as err:
2545 klass=self.__class__,
2546 decode_path=decode_path,
2549 yield decode_path, obj, tail
2552 return pp_console_row(next(self.pps()))
2554 def pps(self, decode_path=()):
2557 asn1_type_name=self.asn1_type_name,
2558 obj_name=self.__class__.__name__,
2559 decode_path=decode_path,
2560 value=(self.named or str(self._value)) if self.ready else None,
2561 optional=self.optional,
2562 default=self == self.default,
2563 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2564 expl=None if self._expl is None else tag_decode(self._expl),
2569 expl_offset=self.expl_offset if self.expled else None,
2570 expl_tlen=self.expl_tlen if self.expled else None,
2571 expl_llen=self.expl_llen if self.expled else None,
2572 expl_vlen=self.expl_vlen if self.expled else None,
2573 expl_lenindef=self.expl_lenindef,
2576 for pp in self.pps_lenindef(decode_path):
2580 BitStringState = namedtuple(
2582 BasicState._fields + ("specs", "value", "tag_constructed", "defined"),
2587 class BitString(Obj):
2588 """``BIT STRING`` bit string type
2590 >>> BitString(b"hello world")
2591 BIT STRING 88 bits 68656c6c6f20776f726c64
2594 >>> b == b"hello world"
2599 >>> BitString("'0A3B5F291CD'H")
2600 BIT STRING 44 bits 0a3b5f291cd0
2601 >>> b = BitString("'010110000000'B")
2602 BIT STRING 12 bits 5800
2605 >>> b[0], b[1], b[2], b[3]
2606 (False, True, False, True)
2610 [False, True, False, True, True, False, False, False, False, False, False, False]
2614 class KeyUsage(BitString):
2616 ("digitalSignature", 0),
2617 ("nonRepudiation", 1),
2618 ("keyEncipherment", 2),
2621 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2622 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2624 ['nonRepudiation', 'keyEncipherment']
2626 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2630 Pay attention that BIT STRING can be encoded both in primitive
2631 and constructed forms. Decoder always checks constructed form tag
2632 additionally to specified primitive one. If BER decoding is
2633 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2634 of DER restrictions.
2636 __slots__ = ("tag_constructed", "specs", "defined")
2637 tag_default = tag_encode(3)
2638 asn1_type_name = "BIT STRING"
2651 :param value: set the value. Either binary type, tuple of named
2652 values (if ``schema`` is specified in the class),
2653 string in ``'XXX...'B`` form, or
2654 :py:class:`pyderasn.BitString` object
2655 :param bytes impl: override default tag with ``IMPLICIT`` one
2656 :param bytes expl: override default tag with ``EXPLICIT`` one
2657 :param default: set default value. Type same as in ``value``
2658 :param bool optional: is object ``OPTIONAL`` in sequence
2660 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2661 specs = getattr(self, "schema", {}) if _specs is None else _specs
2662 self.specs = specs if specs.__class__ == dict else dict(specs)
2663 self._value = None if value is None else self._value_sanitize(value)
2664 if default is not None:
2665 default = self._value_sanitize(default)
2666 self.default = self.__class__(
2672 self._value = default
2674 tag_klass, _, tag_num = tag_decode(self.tag)
2675 self.tag_constructed = tag_encode(
2677 form=TagFormConstructed,
2681 def _bits2octets(self, bits):
2682 if len(self.specs) > 0:
2683 bits = bits.rstrip("0")
2685 bits += "0" * ((8 - (bit_len % 8)) % 8)
2686 octets = bytearray(len(bits) // 8)
2687 for i in six_xrange(len(octets)):
2688 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2689 return bit_len, bytes(octets)
2691 def _value_sanitize(self, value):
2692 if isinstance(value, (string_types, binary_type)):
2694 isinstance(value, string_types) and
2695 value.startswith("'")
2697 if value.endswith("'B"):
2699 if not frozenset(value) <= SET01:
2700 raise ValueError("B's coding contains unacceptable chars")
2701 return self._bits2octets(value)
2702 if value.endswith("'H"):
2706 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2708 if value.__class__ == binary_type:
2709 return (len(value) * 8, value)
2710 raise InvalidValueType((self.__class__, string_types, binary_type))
2711 if value.__class__ == tuple:
2714 isinstance(value[0], integer_types) and
2715 value[1].__class__ == binary_type
2720 bit = self.specs.get(name)
2722 raise ObjUnknown("BitString value: %s" % name)
2725 return self._bits2octets("")
2726 bits = frozenset(bits)
2727 return self._bits2octets("".join(
2728 ("1" if bit in bits else "0")
2729 for bit in six_xrange(max(bits) + 1)
2731 if issubclass(value.__class__, BitString):
2733 raise InvalidValueType((self.__class__, binary_type, string_types))
2737 return self._value is not None
2739 def __getstate__(self):
2740 return BitStringState(
2755 self.tag_constructed,
2759 def __setstate__(self, state):
2760 super(BitString, self).__setstate__(state)
2761 self.specs = state.specs
2762 self._value = state.value
2763 self.tag_constructed = state.tag_constructed
2764 self.defined = state.defined
2767 self._assert_ready()
2768 for i in six_xrange(self._value[0]):
2773 """Returns number of bits in the string
2775 self._assert_ready()
2776 return self._value[0]
2778 def __bytes__(self):
2779 self._assert_ready()
2780 return self._value[1]
2782 def __eq__(self, their):
2783 if their.__class__ == bytes:
2784 return self._value[1] == their
2785 if not issubclass(their.__class__, BitString):
2788 self._value == their._value and
2789 self.tag == their.tag and
2790 self._expl == their._expl
2795 """Named representation (if exists) of the bits
2797 :returns: [str(name), ...]
2799 return [name for name, bit in iteritems(self.specs) if self[bit]]
2809 return self.__class__(
2811 impl=self.tag if impl is None else impl,
2812 expl=self._expl if expl is None else expl,
2813 default=self.default if default is None else default,
2814 optional=self.optional if optional is None else optional,
2818 def __getitem__(self, key):
2819 if key.__class__ == int:
2820 bit_len, octets = self._value
2824 byte2int(memoryview(octets)[key // 8:]) >>
2827 if isinstance(key, string_types):
2828 value = self.specs.get(key)
2830 raise ObjUnknown("BitString value: %s" % key)
2832 raise InvalidValueType((int, str))
2835 self._assert_ready()
2836 bit_len, octets = self._value
2839 len_encode(len(octets) + 1),
2840 int2byte((8 - bit_len % 8) % 8),
2844 def _encode_cer(self, writer):
2845 bit_len, octets = self._value
2846 if len(octets) + 1 <= 1000:
2847 write_full(writer, self._encode())
2849 write_full(writer, self.tag_constructed)
2850 write_full(writer, LENINDEF)
2851 for offset in six_xrange(0, (len(octets) // 999) * 999, 999):
2852 write_full(writer, b"".join((
2853 BitString.tag_default,
2856 octets[offset:offset + 999],
2858 tail = octets[offset+999:]
2860 tail = int2byte((8 - bit_len % 8) % 8) + tail
2861 write_full(writer, b"".join((
2862 BitString.tag_default,
2863 len_encode(len(tail)),
2866 write_full(writer, EOC)
2868 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2870 t, tlen, lv = tag_strip(tlv)
2871 except DecodeError as err:
2872 raise err.__class__(
2874 klass=self.__class__,
2875 decode_path=decode_path,
2879 if tag_only: # pragma: no cover
2883 l, llen, v = len_decode(lv)
2884 except DecodeError as err:
2885 raise err.__class__(
2887 klass=self.__class__,
2888 decode_path=decode_path,
2892 raise NotEnoughData(
2893 "encoded length is longer than data",
2894 klass=self.__class__,
2895 decode_path=decode_path,
2899 raise NotEnoughData(
2901 klass=self.__class__,
2902 decode_path=decode_path,
2905 pad_size = byte2int(v)
2906 if l == 1 and pad_size != 0:
2908 "invalid empty value",
2909 klass=self.__class__,
2910 decode_path=decode_path,
2916 klass=self.__class__,
2917 decode_path=decode_path,
2920 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2923 klass=self.__class__,
2924 decode_path=decode_path,
2927 v, tail = v[:l], v[l:]
2928 bit_len = (len(v) - 1) * 8 - pad_size
2929 obj = self.__class__(
2930 value=None if evgen_mode else (bit_len, v[1:].tobytes()),
2933 default=self.default,
2934 optional=self.optional,
2936 _decoded=(offset, llen, l),
2939 obj._value = (bit_len, None)
2940 yield decode_path, obj, tail
2942 if t != self.tag_constructed:
2944 klass=self.__class__,
2945 decode_path=decode_path,
2948 if not ctx.get("bered", False):
2950 "unallowed BER constructed encoding",
2951 klass=self.__class__,
2952 decode_path=decode_path,
2955 if tag_only: # pragma: no cover
2960 l, llen, v = len_decode(lv)
2961 except LenIndefForm:
2962 llen, l, v = 1, 0, lv[1:]
2964 except DecodeError as err:
2965 raise err.__class__(
2967 klass=self.__class__,
2968 decode_path=decode_path,
2972 raise NotEnoughData(
2973 "encoded length is longer than data",
2974 klass=self.__class__,
2975 decode_path=decode_path,
2978 if not lenindef and l == 0:
2979 raise NotEnoughData(
2981 klass=self.__class__,
2982 decode_path=decode_path,
2986 sub_offset = offset + tlen + llen
2990 if v[:EOC_LEN].tobytes() == EOC:
2997 "chunk out of bounds",
2998 klass=self.__class__,
2999 decode_path=decode_path + (str(len(chunks) - 1),),
3000 offset=chunks[-1].offset,
3002 sub_decode_path = decode_path + (str(len(chunks)),)
3005 for _decode_path, chunk, v_tail in BitString().decode_evgen(
3008 decode_path=sub_decode_path,
3011 _ctx_immutable=False,
3013 yield _decode_path, chunk, v_tail
3015 _, chunk, v_tail = next(BitString().decode_evgen(
3018 decode_path=sub_decode_path,
3021 _ctx_immutable=False,
3026 "expected BitString encoded chunk",
3027 klass=self.__class__,
3028 decode_path=sub_decode_path,
3031 chunks.append(chunk)
3032 sub_offset += chunk.tlvlen
3033 vlen += chunk.tlvlen
3035 if len(chunks) == 0:
3038 klass=self.__class__,
3039 decode_path=decode_path,
3044 for chunk_i, chunk in enumerate(chunks[:-1]):
3045 if chunk.bit_len % 8 != 0:
3047 "BitString chunk is not multiple of 8 bits",
3048 klass=self.__class__,
3049 decode_path=decode_path + (str(chunk_i),),
3050 offset=chunk.offset,
3053 values.append(bytes(chunk))
3054 bit_len += chunk.bit_len
3055 chunk_last = chunks[-1]
3057 values.append(bytes(chunk_last))
3058 bit_len += chunk_last.bit_len
3059 obj = self.__class__(
3060 value=None if evgen_mode else (bit_len, b"".join(values)),
3063 default=self.default,
3064 optional=self.optional,
3066 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3069 obj._value = (bit_len, None)
3070 obj.lenindef = lenindef
3071 obj.ber_encoded = True
3072 yield decode_path, obj, (v[EOC_LEN:] if lenindef else v)
3075 return pp_console_row(next(self.pps()))
3077 def pps(self, decode_path=()):
3081 bit_len, blob = self._value
3082 value = "%d bits" % bit_len
3083 if len(self.specs) > 0 and blob is not None:
3084 blob = tuple(self.named)
3087 asn1_type_name=self.asn1_type_name,
3088 obj_name=self.__class__.__name__,
3089 decode_path=decode_path,
3092 optional=self.optional,
3093 default=self == self.default,
3094 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3095 expl=None if self._expl is None else tag_decode(self._expl),
3100 expl_offset=self.expl_offset if self.expled else None,
3101 expl_tlen=self.expl_tlen if self.expled else None,
3102 expl_llen=self.expl_llen if self.expled else None,
3103 expl_vlen=self.expl_vlen if self.expled else None,
3104 expl_lenindef=self.expl_lenindef,
3105 lenindef=self.lenindef,
3106 ber_encoded=self.ber_encoded,
3109 defined_by, defined = self.defined or (None, None)
3110 if defined_by is not None:
3112 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3114 for pp in self.pps_lenindef(decode_path):
3118 OctetStringState = namedtuple(
3120 BasicState._fields + (
3131 class OctetString(Obj):
3132 """``OCTET STRING`` binary string type
3134 >>> s = OctetString(b"hello world")
3135 OCTET STRING 11 bytes 68656c6c6f20776f726c64
3136 >>> s == OctetString(b"hello world")
3141 >>> OctetString(b"hello", bounds=(4, 4))
3142 Traceback (most recent call last):
3143 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
3144 >>> OctetString(b"hell", bounds=(4, 4))
3145 OCTET STRING 4 bytes 68656c6c
3149 Pay attention that OCTET STRING can be encoded both in primitive
3150 and constructed forms. Decoder always checks constructed form tag
3151 additionally to specified primitive one. If BER decoding is
3152 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
3153 of DER restrictions.
3155 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
3156 tag_default = tag_encode(4)
3157 asn1_type_name = "OCTET STRING"
3158 evgen_mode_skip_value = True
3172 :param value: set the value. Either binary type, or
3173 :py:class:`pyderasn.OctetString` object
3174 :param bounds: set ``(MIN, MAX)`` value size constraint.
3175 (-inf, +inf) by default
3176 :param bytes impl: override default tag with ``IMPLICIT`` one
3177 :param bytes expl: override default tag with ``EXPLICIT`` one
3178 :param default: set default value. Type same as in ``value``
3179 :param bool optional: is object ``OPTIONAL`` in sequence
3181 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
3183 self._bound_min, self._bound_max = getattr(
3187 ) if bounds is None else bounds
3188 if value is not None:
3189 self._value = self._value_sanitize(value)
3190 if default is not None:
3191 default = self._value_sanitize(default)
3192 self.default = self.__class__(
3197 if self._value is None:
3198 self._value = default
3200 tag_klass, _, tag_num = tag_decode(self.tag)
3201 self.tag_constructed = tag_encode(
3203 form=TagFormConstructed,
3207 def _value_sanitize(self, value):
3208 if value.__class__ == binary_type:
3210 elif issubclass(value.__class__, OctetString):
3211 value = value._value
3213 raise InvalidValueType((self.__class__, bytes))
3214 if not self._bound_min <= len(value) <= self._bound_max:
3215 raise BoundsError(self._bound_min, len(value), self._bound_max)
3220 return self._value is not None
3222 def __getstate__(self):
3223 return OctetStringState(
3239 self.tag_constructed,
3243 def __setstate__(self, state):
3244 super(OctetString, self).__setstate__(state)
3245 self._value = state.value
3246 self._bound_min = state.bound_min
3247 self._bound_max = state.bound_max
3248 self.tag_constructed = state.tag_constructed
3249 self.defined = state.defined
3251 def __bytes__(self):
3252 self._assert_ready()
3255 def __eq__(self, their):
3256 if their.__class__ == binary_type:
3257 return self._value == their
3258 if not issubclass(their.__class__, OctetString):
3261 self._value == their._value and
3262 self.tag == their.tag and
3263 self._expl == their._expl
3266 def __lt__(self, their):
3267 return self._value < their._value
3278 return self.__class__(
3281 (self._bound_min, self._bound_max)
3282 if bounds is None else bounds
3284 impl=self.tag if impl is None else impl,
3285 expl=self._expl if expl is None else expl,
3286 default=self.default if default is None else default,
3287 optional=self.optional if optional is None else optional,
3291 self._assert_ready()
3294 len_encode(len(self._value)),
3298 def _encode_cer(self, writer):
3299 octets = self._value
3300 if len(octets) <= 1000:
3301 write_full(writer, self._encode())
3303 write_full(writer, self.tag_constructed)
3304 write_full(writer, LENINDEF)
3305 for offset in six_xrange(0, (len(octets) // 1000) * 1000, 1000):
3306 write_full(writer, b"".join((
3307 OctetString.tag_default,
3309 octets[offset:offset + 1000],
3311 tail = octets[offset+1000:]
3313 write_full(writer, b"".join((
3314 OctetString.tag_default,
3315 len_encode(len(tail)),
3318 write_full(writer, EOC)
3320 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3322 t, tlen, lv = tag_strip(tlv)
3323 except DecodeError as err:
3324 raise err.__class__(
3326 klass=self.__class__,
3327 decode_path=decode_path,
3335 l, llen, v = len_decode(lv)
3336 except DecodeError as err:
3337 raise err.__class__(
3339 klass=self.__class__,
3340 decode_path=decode_path,
3344 raise NotEnoughData(
3345 "encoded length is longer than data",
3346 klass=self.__class__,
3347 decode_path=decode_path,
3350 v, tail = v[:l], v[l:]
3351 if evgen_mode and not self._bound_min <= len(v) <= self._bound_max:
3353 msg=str(BoundsError(self._bound_min, len(v), self._bound_max)),
3354 klass=self.__class__,
3355 decode_path=decode_path,
3359 obj = self.__class__(
3361 None if (evgen_mode and self.evgen_mode_skip_value)
3364 bounds=(self._bound_min, self._bound_max),
3367 default=self.default,
3368 optional=self.optional,
3369 _decoded=(offset, llen, l),
3372 except DecodeError as err:
3375 klass=self.__class__,
3376 decode_path=decode_path,
3379 except BoundsError as err:
3382 klass=self.__class__,
3383 decode_path=decode_path,
3386 yield decode_path, obj, tail
3388 if t != self.tag_constructed:
3390 klass=self.__class__,
3391 decode_path=decode_path,
3394 if not ctx.get("bered", False):
3396 "unallowed BER constructed encoding",
3397 klass=self.__class__,
3398 decode_path=decode_path,
3406 l, llen, v = len_decode(lv)
3407 except LenIndefForm:
3408 llen, l, v = 1, 0, lv[1:]
3410 except DecodeError as err:
3411 raise err.__class__(
3413 klass=self.__class__,
3414 decode_path=decode_path,
3418 raise NotEnoughData(
3419 "encoded length is longer than data",
3420 klass=self.__class__,
3421 decode_path=decode_path,
3426 sub_offset = offset + tlen + llen
3431 if v[:EOC_LEN].tobytes() == EOC:
3438 "chunk out of bounds",
3439 klass=self.__class__,
3440 decode_path=decode_path + (str(len(chunks) - 1),),
3441 offset=chunks[-1].offset,
3445 sub_decode_path = decode_path + (str(chunks_count),)
3446 for _decode_path, chunk, v_tail in OctetString().decode_evgen(
3449 decode_path=sub_decode_path,
3452 _ctx_immutable=False,
3454 yield _decode_path, chunk, v_tail
3455 if not chunk.ber_encoded:
3456 payload_len += chunk.vlen
3459 sub_decode_path = decode_path + (str(len(chunks)),)
3460 _, chunk, v_tail = next(OctetString().decode_evgen(
3463 decode_path=sub_decode_path,
3466 _ctx_immutable=False,
3469 chunks.append(chunk)
3472 "expected OctetString encoded chunk",
3473 klass=self.__class__,
3474 decode_path=sub_decode_path,
3477 sub_offset += chunk.tlvlen
3478 vlen += chunk.tlvlen
3480 if evgen_mode and not self._bound_min <= payload_len <= self._bound_max:
3482 msg=str(BoundsError(self._bound_min, payload_len, self._bound_max)),
3483 klass=self.__class__,
3484 decode_path=decode_path,
3488 obj = self.__class__(
3490 None if evgen_mode else
3491 b"".join(bytes(chunk) for chunk in chunks)
3493 bounds=(self._bound_min, self._bound_max),
3496 default=self.default,
3497 optional=self.optional,
3498 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3501 except DecodeError as err:
3504 klass=self.__class__,
3505 decode_path=decode_path,
3508 except BoundsError as err:
3511 klass=self.__class__,
3512 decode_path=decode_path,
3515 obj.lenindef = lenindef
3516 obj.ber_encoded = True
3517 yield decode_path, obj, (v[EOC_LEN:] if lenindef else v)
3520 return pp_console_row(next(self.pps()))
3522 def pps(self, decode_path=()):
3525 asn1_type_name=self.asn1_type_name,
3526 obj_name=self.__class__.__name__,
3527 decode_path=decode_path,
3528 value=("%d bytes" % len(self._value)) if self.ready else None,
3529 blob=self._value if self.ready else None,
3530 optional=self.optional,
3531 default=self == self.default,
3532 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3533 expl=None if self._expl is None else tag_decode(self._expl),
3538 expl_offset=self.expl_offset if self.expled else None,
3539 expl_tlen=self.expl_tlen if self.expled else None,
3540 expl_llen=self.expl_llen if self.expled else None,
3541 expl_vlen=self.expl_vlen if self.expled else None,
3542 expl_lenindef=self.expl_lenindef,
3543 lenindef=self.lenindef,
3544 ber_encoded=self.ber_encoded,
3547 defined_by, defined = self.defined or (None, None)
3548 if defined_by is not None:
3550 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3552 for pp in self.pps_lenindef(decode_path):
3556 NullState = namedtuple("NullState", BasicState._fields, **NAMEDTUPLE_KWARGS)
3560 """``NULL`` null object
3568 tag_default = tag_encode(5)
3569 asn1_type_name = "NULL"
3573 value=None, # unused, but Sequence passes it
3580 :param bytes impl: override default tag with ``IMPLICIT`` one
3581 :param bytes expl: override default tag with ``EXPLICIT`` one
3582 :param bool optional: is object ``OPTIONAL`` in sequence
3584 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3591 def __getstate__(self):
3607 def __eq__(self, their):
3608 if not issubclass(their.__class__, Null):
3611 self.tag == their.tag and
3612 self._expl == their._expl
3622 return self.__class__(
3623 impl=self.tag if impl is None else impl,
3624 expl=self._expl if expl is None else expl,
3625 optional=self.optional if optional is None else optional,
3629 return self.tag + len_encode(0)
3631 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3633 t, _, lv = tag_strip(tlv)
3634 except DecodeError as err:
3635 raise err.__class__(
3637 klass=self.__class__,
3638 decode_path=decode_path,
3643 klass=self.__class__,
3644 decode_path=decode_path,
3647 if tag_only: # pragma: no cover
3651 l, _, v = len_decode(lv)
3652 except DecodeError as err:
3653 raise err.__class__(
3655 klass=self.__class__,
3656 decode_path=decode_path,
3660 raise InvalidLength(
3661 "Null must have zero length",
3662 klass=self.__class__,
3663 decode_path=decode_path,
3666 obj = self.__class__(
3669 optional=self.optional,
3670 _decoded=(offset, 1, 0),
3672 yield decode_path, obj, v
3675 return pp_console_row(next(self.pps()))
3677 def pps(self, decode_path=()):
3680 asn1_type_name=self.asn1_type_name,
3681 obj_name=self.__class__.__name__,
3682 decode_path=decode_path,
3683 optional=self.optional,
3684 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3685 expl=None if self._expl is None else tag_decode(self._expl),
3690 expl_offset=self.expl_offset if self.expled else None,
3691 expl_tlen=self.expl_tlen if self.expled else None,
3692 expl_llen=self.expl_llen if self.expled else None,
3693 expl_vlen=self.expl_vlen if self.expled else None,
3694 expl_lenindef=self.expl_lenindef,
3697 for pp in self.pps_lenindef(decode_path):
3701 ObjectIdentifierState = namedtuple(
3702 "ObjectIdentifierState",
3703 BasicState._fields + ("value", "defines"),
3708 class ObjectIdentifier(Obj):
3709 """``OBJECT IDENTIFIER`` OID type
3711 >>> oid = ObjectIdentifier((1, 2, 3))
3712 OBJECT IDENTIFIER 1.2.3
3713 >>> oid == ObjectIdentifier("1.2.3")
3719 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3720 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3722 >>> str(ObjectIdentifier((3, 1)))
3723 Traceback (most recent call last):
3724 pyderasn.InvalidOID: unacceptable first arc value
3726 __slots__ = ("defines",)
3727 tag_default = tag_encode(6)
3728 asn1_type_name = "OBJECT IDENTIFIER"
3741 :param value: set the value. Either tuples of integers,
3742 string of "."-concatenated integers, or
3743 :py:class:`pyderasn.ObjectIdentifier` object
3744 :param defines: sequence of tuples. Each tuple has two elements.
3745 First one is relative to current one decode
3746 path, aiming to the field defined by that OID.
3747 Read about relative path in
3748 :py:func:`pyderasn.abs_decode_path`. Second
3749 tuple element is ``{OID: pyderasn.Obj()}``
3750 dictionary, mapping between current OID value
3751 and structure applied to defined field.
3752 :ref:`Read about DEFINED BY <definedby>`
3753 :param bytes impl: override default tag with ``IMPLICIT`` one
3754 :param bytes expl: override default tag with ``EXPLICIT`` one
3755 :param default: set default value. Type same as in ``value``
3756 :param bool optional: is object ``OPTIONAL`` in sequence
3758 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3760 if value is not None:
3761 self._value = self._value_sanitize(value)
3762 if default is not None:
3763 default = self._value_sanitize(default)
3764 self.default = self.__class__(
3769 if self._value is None:
3770 self._value = default
3771 self.defines = defines
3773 def __add__(self, their):
3774 if their.__class__ == tuple:
3775 return self.__class__(self._value + their)
3776 if isinstance(their, self.__class__):
3777 return self.__class__(self._value + their._value)
3778 raise InvalidValueType((self.__class__, tuple))
3780 def _value_sanitize(self, value):
3781 if issubclass(value.__class__, ObjectIdentifier):
3783 if isinstance(value, string_types):
3785 value = tuple(pureint(arc) for arc in value.split("."))
3787 raise InvalidOID("unacceptable arcs values")
3788 if value.__class__ == tuple:
3790 raise InvalidOID("less than 2 arcs")
3791 first_arc = value[0]
3792 if first_arc in (0, 1):
3793 if not (0 <= value[1] <= 39):
3794 raise InvalidOID("second arc is too wide")
3795 elif first_arc == 2:
3798 raise InvalidOID("unacceptable first arc value")
3799 if not all(arc >= 0 for arc in value):
3800 raise InvalidOID("negative arc value")
3802 raise InvalidValueType((self.__class__, str, tuple))
3806 return self._value is not None
3808 def __getstate__(self):
3809 return ObjectIdentifierState(
3826 def __setstate__(self, state):
3827 super(ObjectIdentifier, self).__setstate__(state)
3828 self._value = state.value
3829 self.defines = state.defines
3832 self._assert_ready()
3833 return iter(self._value)
3836 return ".".join(str(arc) for arc in self._value or ())
3839 self._assert_ready()
3842 bytes(self._expl or b"") +
3843 str(self._value).encode("ascii"),
3846 def __eq__(self, their):
3847 if their.__class__ == tuple:
3848 return self._value == their
3849 if not issubclass(their.__class__, ObjectIdentifier):
3852 self.tag == their.tag and
3853 self._expl == their._expl and
3854 self._value == their._value
3857 def __lt__(self, their):
3858 return self._value < their._value
3869 return self.__class__(
3871 defines=self.defines if defines is None else defines,
3872 impl=self.tag if impl is None else impl,
3873 expl=self._expl if expl is None else expl,
3874 default=self.default if default is None else default,
3875 optional=self.optional if optional is None else optional,
3879 self._assert_ready()
3881 first_value = value[1]
3882 first_arc = value[0]
3885 elif first_arc == 1:
3887 elif first_arc == 2:
3889 else: # pragma: no cover
3890 raise RuntimeError("invalid arc is stored")
3891 octets = [zero_ended_encode(first_value)]
3892 for arc in value[2:]:
3893 octets.append(zero_ended_encode(arc))
3894 v = b"".join(octets)
3895 return b"".join((self.tag, len_encode(len(v)), v))
3897 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3899 t, _, lv = tag_strip(tlv)
3900 except DecodeError as err:
3901 raise err.__class__(
3903 klass=self.__class__,
3904 decode_path=decode_path,
3909 klass=self.__class__,
3910 decode_path=decode_path,
3913 if tag_only: # pragma: no cover
3917 l, llen, v = len_decode(lv)
3918 except DecodeError as err:
3919 raise err.__class__(
3921 klass=self.__class__,
3922 decode_path=decode_path,
3926 raise NotEnoughData(
3927 "encoded length is longer than data",
3928 klass=self.__class__,
3929 decode_path=decode_path,
3933 raise NotEnoughData(
3935 klass=self.__class__,
3936 decode_path=decode_path,
3939 v, tail = v[:l], v[l:]
3946 octet = indexbytes(v, i)
3947 if i == 0 and octet == 0x80:
3948 if ctx.get("bered", False):
3951 raise DecodeError("non normalized arc encoding")
3952 arc = (arc << 7) | (octet & 0x7F)
3953 if octet & 0x80 == 0:
3961 klass=self.__class__,
3962 decode_path=decode_path,
3966 second_arc = arcs[0]
3967 if 0 <= second_arc <= 39:
3969 elif 40 <= second_arc <= 79:
3975 obj = self.__class__(
3976 value=tuple([first_arc, second_arc] + arcs[1:]),
3979 default=self.default,
3980 optional=self.optional,
3981 _decoded=(offset, llen, l),
3984 obj.ber_encoded = True
3985 yield decode_path, obj, tail
3988 return pp_console_row(next(self.pps()))
3990 def pps(self, decode_path=()):
3993 asn1_type_name=self.asn1_type_name,
3994 obj_name=self.__class__.__name__,
3995 decode_path=decode_path,
3996 value=str(self) if self.ready else None,
3997 optional=self.optional,
3998 default=self == self.default,
3999 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4000 expl=None if self._expl is None else tag_decode(self._expl),
4005 expl_offset=self.expl_offset if self.expled else None,
4006 expl_tlen=self.expl_tlen if self.expled else None,
4007 expl_llen=self.expl_llen if self.expled else None,
4008 expl_vlen=self.expl_vlen if self.expled else None,
4009 expl_lenindef=self.expl_lenindef,
4010 ber_encoded=self.ber_encoded,
4013 for pp in self.pps_lenindef(decode_path):
4017 class Enumerated(Integer):
4018 """``ENUMERATED`` integer type
4020 This type is identical to :py:class:`pyderasn.Integer`, but requires
4021 schema to be specified and does not accept values missing from it.
4024 tag_default = tag_encode(10)
4025 asn1_type_name = "ENUMERATED"
4036 bounds=None, # dummy argument, workability for Integer.decode
4038 super(Enumerated, self).__init__(
4039 value, bounds, impl, expl, default, optional, _specs, _decoded,
4041 if len(self.specs) == 0:
4042 raise ValueError("schema must be specified")
4044 def _value_sanitize(self, value):
4045 if isinstance(value, self.__class__):
4046 value = value._value
4047 elif isinstance(value, integer_types):
4048 for _value in itervalues(self.specs):
4053 "unknown integer value: %s" % value,
4054 klass=self.__class__,
4056 elif isinstance(value, string_types):
4057 value = self.specs.get(value)
4059 raise ObjUnknown("integer value: %s" % value)
4061 raise InvalidValueType((self.__class__, int, str))
4073 return self.__class__(
4075 impl=self.tag if impl is None else impl,
4076 expl=self._expl if expl is None else expl,
4077 default=self.default if default is None else default,
4078 optional=self.optional if optional is None else optional,
4083 def escape_control_unicode(c):
4084 if unicat(c)[0] == "C":
4085 c = repr(c).lstrip("u").strip("'")
4089 class CommonString(OctetString):
4090 """Common class for all strings
4092 Everything resembles :py:class:`pyderasn.OctetString`, except
4093 ability to deal with unicode text strings.
4095 >>> hexenc("привет мир".encode("utf-8"))
4096 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
4097 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
4099 >>> s = UTF8String("привет мир")
4100 UTF8String UTF8String привет мир
4102 'привет мир'
4103 >>> hexenc(bytes(s))
4104 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
4106 >>> PrintableString("привет мир")
4107 Traceback (most recent call last):
4108 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
4110 >>> BMPString("ада", bounds=(2, 2))
4111 Traceback (most recent call last):
4112 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
4113 >>> s = BMPString("ад", bounds=(2, 2))
4116 >>> hexenc(bytes(s))
4124 * - :py:class:`pyderasn.UTF8String`
4126 * - :py:class:`pyderasn.NumericString`
4128 * - :py:class:`pyderasn.PrintableString`
4130 * - :py:class:`pyderasn.TeletexString`
4132 * - :py:class:`pyderasn.T61String`
4134 * - :py:class:`pyderasn.VideotexString`
4136 * - :py:class:`pyderasn.IA5String`
4138 * - :py:class:`pyderasn.GraphicString`
4140 * - :py:class:`pyderasn.VisibleString`
4142 * - :py:class:`pyderasn.ISO646String`
4144 * - :py:class:`pyderasn.GeneralString`
4146 * - :py:class:`pyderasn.UniversalString`
4148 * - :py:class:`pyderasn.BMPString`
4153 def _value_sanitize(self, value):
4155 value_decoded = None
4156 if isinstance(value, self.__class__):
4157 value_raw = value._value
4158 elif value.__class__ == text_type:
4159 value_decoded = value
4160 elif value.__class__ == binary_type:
4163 raise InvalidValueType((self.__class__, text_type, binary_type))
4166 value_decoded.encode(self.encoding)
4167 if value_raw is None else value_raw
4170 value_raw.decode(self.encoding)
4171 if value_decoded is None else value_decoded
4173 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4174 raise DecodeError(str(err))
4175 if not self._bound_min <= len(value_decoded) <= self._bound_max:
4183 def __eq__(self, their):
4184 if their.__class__ == binary_type:
4185 return self._value == their
4186 if their.__class__ == text_type:
4187 return self._value == their.encode(self.encoding)
4188 if not isinstance(their, self.__class__):
4191 self._value == their._value and
4192 self.tag == their.tag and
4193 self._expl == their._expl
4196 def __unicode__(self):
4198 return self._value.decode(self.encoding)
4199 return text_type(self._value)
4202 return pp_console_row(next(self.pps(no_unicode=PY2)))
4204 def pps(self, decode_path=(), no_unicode=False):
4208 hexenc(bytes(self)) if no_unicode else
4209 "".join(escape_control_unicode(c) for c in self.__unicode__())
4213 asn1_type_name=self.asn1_type_name,
4214 obj_name=self.__class__.__name__,
4215 decode_path=decode_path,
4217 optional=self.optional,
4218 default=self == self.default,
4219 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4220 expl=None if self._expl is None else tag_decode(self._expl),
4225 expl_offset=self.expl_offset if self.expled else None,
4226 expl_tlen=self.expl_tlen if self.expled else None,
4227 expl_llen=self.expl_llen if self.expled else None,
4228 expl_vlen=self.expl_vlen if self.expled else None,
4229 expl_lenindef=self.expl_lenindef,
4230 ber_encoded=self.ber_encoded,
4233 for pp in self.pps_lenindef(decode_path):
4237 class UTF8String(CommonString):
4239 tag_default = tag_encode(12)
4241 asn1_type_name = "UTF8String"
4244 class AllowableCharsMixin(object):
4246 def allowable_chars(self):
4248 return self._allowable_chars
4249 return frozenset(six_unichr(c) for c in self._allowable_chars)
4252 class NumericString(AllowableCharsMixin, CommonString):
4255 Its value is properly sanitized: only ASCII digits with spaces can
4258 >>> NumericString().allowable_chars
4259 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
4262 tag_default = tag_encode(18)
4264 asn1_type_name = "NumericString"
4265 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
4267 def _value_sanitize(self, value):
4268 value = super(NumericString, self)._value_sanitize(value)
4269 if not frozenset(value) <= self._allowable_chars:
4270 raise DecodeError("non-numeric value")
4274 PrintableStringState = namedtuple(
4275 "PrintableStringState",
4276 OctetStringState._fields + ("allowable_chars",),
4281 class PrintableString(AllowableCharsMixin, CommonString):
4284 Its value is properly sanitized: see X.680 41.4 table 10.
4286 >>> PrintableString().allowable_chars
4287 frozenset([' ', "'", ..., 'z'])
4288 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4289 PrintableString PrintableString foo*bar
4290 >>> obj.allow_asterisk, obj.allow_ampersand
4294 tag_default = tag_encode(19)
4296 asn1_type_name = "PrintableString"
4297 _allowable_chars = frozenset(
4298 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4300 _asterisk = frozenset("*".encode("ascii"))
4301 _ampersand = frozenset("&".encode("ascii"))
4313 allow_asterisk=False,
4314 allow_ampersand=False,
4317 :param allow_asterisk: allow asterisk character
4318 :param allow_ampersand: allow ampersand character
4321 self._allowable_chars |= self._asterisk
4323 self._allowable_chars |= self._ampersand
4324 super(PrintableString, self).__init__(
4325 value, bounds, impl, expl, default, optional, _decoded, ctx,
4329 def allow_asterisk(self):
4330 """Is asterisk character allowed?
4332 return self._asterisk <= self._allowable_chars
4335 def allow_ampersand(self):
4336 """Is ampersand character allowed?
4338 return self._ampersand <= self._allowable_chars
4340 def _value_sanitize(self, value):
4341 value = super(PrintableString, self)._value_sanitize(value)
4342 if not frozenset(value) <= self._allowable_chars:
4343 raise DecodeError("non-printable value")
4346 def __getstate__(self):
4347 return PrintableStringState(
4348 *super(PrintableString, self).__getstate__(),
4349 **{"allowable_chars": self._allowable_chars}
4352 def __setstate__(self, state):
4353 super(PrintableString, self).__setstate__(state)
4354 self._allowable_chars = state.allowable_chars
4365 return self.__class__(
4368 (self._bound_min, self._bound_max)
4369 if bounds is None else bounds
4371 impl=self.tag if impl is None else impl,
4372 expl=self._expl if expl is None else expl,
4373 default=self.default if default is None else default,
4374 optional=self.optional if optional is None else optional,
4375 allow_asterisk=self.allow_asterisk,
4376 allow_ampersand=self.allow_ampersand,
4380 class TeletexString(CommonString):
4382 tag_default = tag_encode(20)
4384 asn1_type_name = "TeletexString"
4387 class T61String(TeletexString):
4389 asn1_type_name = "T61String"
4392 class VideotexString(CommonString):
4394 tag_default = tag_encode(21)
4395 encoding = "iso-8859-1"
4396 asn1_type_name = "VideotexString"
4399 class IA5String(CommonString):
4401 tag_default = tag_encode(22)
4403 asn1_type_name = "IA5"
4406 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4407 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4408 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4411 class VisibleString(CommonString):
4413 tag_default = tag_encode(26)
4415 asn1_type_name = "VisibleString"
4418 UTCTimeState = namedtuple(
4420 OctetStringState._fields + ("ber_raw",),
4425 def str_to_time_fractions(value):
4427 year, v = (v // 10**10), (v % 10**10)
4428 month, v = (v // 10**8), (v % 10**8)
4429 day, v = (v // 10**6), (v % 10**6)
4430 hour, v = (v // 10**4), (v % 10**4)
4431 minute, second = (v // 100), (v % 100)
4432 return year, month, day, hour, minute, second
4435 class UTCTime(VisibleString):
4436 """``UTCTime`` datetime type
4438 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4439 UTCTime UTCTime 2017-09-30T22:07:50
4445 datetime.datetime(2017, 9, 30, 22, 7, 50)
4446 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4447 datetime.datetime(1957, 9, 30, 22, 7, 50)
4449 If BER encoded value was met, then ``ber_raw`` attribute will hold
4450 its raw representation.
4454 Pay attention that UTCTime can not hold full year, so all years
4455 having < 50 years are treated as 20xx, 19xx otherwise, according
4456 to X.509 recommendation.
4460 No strict validation of UTC offsets are made, but very crude:
4462 * minutes are not exceeding 60
4463 * offset value is not exceeding 14 hours
4465 __slots__ = ("ber_raw",)
4466 tag_default = tag_encode(23)
4468 asn1_type_name = "UTCTime"
4469 evgen_mode_skip_value = False
4479 bounds=None, # dummy argument, workability for OctetString.decode
4483 :param value: set the value. Either datetime type, or
4484 :py:class:`pyderasn.UTCTime` object
4485 :param bytes impl: override default tag with ``IMPLICIT`` one
4486 :param bytes expl: override default tag with ``EXPLICIT`` one
4487 :param default: set default value. Type same as in ``value``
4488 :param bool optional: is object ``OPTIONAL`` in sequence
4490 super(UTCTime, self).__init__(
4491 None, None, impl, expl, None, optional, _decoded, ctx,
4495 if value is not None:
4496 self._value, self.ber_raw = self._value_sanitize(value, ctx)
4497 self.ber_encoded = self.ber_raw is not None
4498 if default is not None:
4499 default, _ = self._value_sanitize(default)
4500 self.default = self.__class__(
4505 if self._value is None:
4506 self._value = default
4508 self.optional = optional
4510 def _strptime_bered(self, value):
4511 year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
4514 raise ValueError("no timezone")
4515 year += 2000 if year < 50 else 1900
4516 decoded = datetime(year, month, day, hour, minute)
4518 if value[-1] == "Z":
4522 raise ValueError("invalid UTC offset")
4523 if value[-5] == "-":
4525 elif value[-5] == "+":
4528 raise ValueError("invalid UTC offset")
4529 v = pureint(value[-4:])
4530 offset, v = (60 * (v % 100)), v // 100
4532 raise ValueError("invalid UTC offset minutes")
4534 if offset > 14 * 3600:
4535 raise ValueError("too big UTC offset")
4539 return offset, decoded
4541 raise ValueError("invalid UTC offset seconds")
4542 seconds = pureint(value)
4544 raise ValueError("invalid seconds value")
4545 return offset, decoded + timedelta(seconds=seconds)
4547 def _strptime(self, value):
4548 # datetime.strptime's format: %y%m%d%H%M%SZ
4549 if len(value) != LEN_YYMMDDHHMMSSZ:
4550 raise ValueError("invalid UTCTime length")
4551 if value[-1] != "Z":
4552 raise ValueError("non UTC timezone")
4553 year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
4554 year += 2000 if year < 50 else 1900
4555 return datetime(year, month, day, hour, minute, second)
4557 def _dt_sanitize(self, value):
4558 if value.year < 1950 or value.year > 2049:
4559 raise ValueError("UTCTime can hold only 1950-2049 years")
4560 return value.replace(microsecond=0)
4562 def _value_sanitize(self, value, ctx=None):
4563 if value.__class__ == binary_type:
4565 value_decoded = value.decode("ascii")
4566 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4567 raise DecodeError("invalid UTCTime encoding: %r" % err)
4570 return self._strptime(value_decoded), None
4571 except (TypeError, ValueError) as _err:
4573 if (ctx is not None) and ctx.get("bered", False):
4575 offset, _value = self._strptime_bered(value_decoded)
4576 _value = _value - timedelta(seconds=offset)
4577 return self._dt_sanitize(_value), value
4578 except (TypeError, ValueError, OverflowError) as _err:
4581 "invalid %s format: %r" % (self.asn1_type_name, err),
4582 klass=self.__class__,
4584 if isinstance(value, self.__class__):
4585 return value._value, None
4586 if value.__class__ == datetime:
4587 return self._dt_sanitize(value), None
4588 raise InvalidValueType((self.__class__, datetime))
4590 def _pp_value(self):
4592 value = self._value.isoformat()
4593 if self.ber_encoded:
4594 value += " (%s)" % self.ber_raw
4597 def __unicode__(self):
4599 value = self._value.isoformat()
4600 if self.ber_encoded:
4601 value += " (%s)" % self.ber_raw
4603 return text_type(self._pp_value())
4605 def __getstate__(self):
4606 return UTCTimeState(
4607 *super(UTCTime, self).__getstate__(),
4608 **{"ber_raw": self.ber_raw}
4611 def __setstate__(self, state):
4612 super(UTCTime, self).__setstate__(state)
4613 self.ber_raw = state.ber_raw
4615 def __bytes__(self):
4616 self._assert_ready()
4617 return self._encode_time()
4619 def __eq__(self, their):
4620 if their.__class__ == binary_type:
4621 return self._encode_time() == their
4622 if their.__class__ == datetime:
4623 return self.todatetime() == their
4624 if not isinstance(their, self.__class__):
4627 self._value == their._value and
4628 self.tag == their.tag and
4629 self._expl == their._expl
4632 def _encode_time(self):
4633 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4636 self._assert_ready()
4637 value = self._encode_time()
4638 return b"".join((self.tag, len_encode(len(value)), value))
4640 def _encode_cer(self, writer):
4641 write_full(writer, self._encode())
4643 def todatetime(self):
4647 return pp_console_row(next(self.pps()))
4649 def pps(self, decode_path=()):
4652 asn1_type_name=self.asn1_type_name,
4653 obj_name=self.__class__.__name__,
4654 decode_path=decode_path,
4655 value=self._pp_value(),
4656 optional=self.optional,
4657 default=self == self.default,
4658 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4659 expl=None if self._expl is None else tag_decode(self._expl),
4664 expl_offset=self.expl_offset if self.expled else None,
4665 expl_tlen=self.expl_tlen if self.expled else None,
4666 expl_llen=self.expl_llen if self.expled else None,
4667 expl_vlen=self.expl_vlen if self.expled else None,
4668 expl_lenindef=self.expl_lenindef,
4669 ber_encoded=self.ber_encoded,
4672 for pp in self.pps_lenindef(decode_path):
4676 class GeneralizedTime(UTCTime):
4677 """``GeneralizedTime`` datetime type
4679 This type is similar to :py:class:`pyderasn.UTCTime`.
4681 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4682 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4684 '20170930220750.000123Z'
4685 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4686 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4690 Only microsecond fractions are supported in DER encoding.
4691 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4692 higher precision values.
4696 BER encoded data can loss information (accuracy) during decoding
4697 because of float transformations.
4701 Local times (without explicit timezone specification) are treated
4702 as UTC one, no transformations are made.
4706 Zero year is unsupported.
4709 tag_default = tag_encode(24)
4710 asn1_type_name = "GeneralizedTime"
4712 def _dt_sanitize(self, value):
4715 def _strptime_bered(self, value):
4716 if len(value) < 4 + 3 * 2:
4717 raise ValueError("invalid GeneralizedTime")
4718 year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
4719 decoded = datetime(year, month, day, hour)
4720 offset, value = 0, value[10:]
4722 return offset, decoded
4723 if value[-1] == "Z":
4726 for char, sign in (("-", -1), ("+", 1)):
4727 idx = value.rfind(char)
4730 offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
4731 v = pureint(offset_raw)
4732 if len(offset_raw) == 4:
4733 offset, v = (60 * (v % 100)), v // 100
4735 raise ValueError("invalid UTC offset minutes")
4736 elif len(offset_raw) == 2:
4739 raise ValueError("invalid UTC offset")
4741 if offset > 14 * 3600:
4742 raise ValueError("too big UTC offset")
4746 return offset, decoded
4747 if value[0] in DECIMAL_SIGNS:
4749 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4752 raise ValueError("stripped minutes")
4753 decoded += timedelta(seconds=60 * pureint(value[:2]))
4756 return offset, decoded
4757 if value[0] in DECIMAL_SIGNS:
4759 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4762 raise ValueError("stripped seconds")
4763 decoded += timedelta(seconds=pureint(value[:2]))
4766 return offset, decoded
4767 if value[0] not in DECIMAL_SIGNS:
4768 raise ValueError("invalid format after seconds")
4770 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4773 def _strptime(self, value):
4775 if l == LEN_YYYYMMDDHHMMSSZ:
4776 # datetime.strptime's format: %Y%m%d%H%M%SZ
4777 if value[-1] != "Z":
4778 raise ValueError("non UTC timezone")
4779 return datetime(*str_to_time_fractions(value[:-1]))
4780 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4781 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4782 if value[-1] != "Z":
4783 raise ValueError("non UTC timezone")
4784 if value[14] != ".":
4785 raise ValueError("no fractions separator")
4788 raise ValueError("trailing zero")
4791 raise ValueError("only microsecond fractions are supported")
4792 us = pureint(us + ("0" * (6 - us_len)))
4793 year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
4794 return datetime(year, month, day, hour, minute, second, us)
4795 raise ValueError("invalid GeneralizedTime length")
4797 def _encode_time(self):
4799 encoded = value.strftime("%Y%m%d%H%M%S")
4800 if value.microsecond > 0:
4801 encoded += (".%06d" % value.microsecond).rstrip("0")
4802 return (encoded + "Z").encode("ascii")
4805 class GraphicString(CommonString):
4807 tag_default = tag_encode(25)
4808 encoding = "iso-8859-1"
4809 asn1_type_name = "GraphicString"
4812 class ISO646String(VisibleString):
4814 asn1_type_name = "ISO646String"
4817 class GeneralString(CommonString):
4819 tag_default = tag_encode(27)
4820 encoding = "iso-8859-1"
4821 asn1_type_name = "GeneralString"
4824 class UniversalString(CommonString):
4826 tag_default = tag_encode(28)
4827 encoding = "utf-32-be"
4828 asn1_type_name = "UniversalString"
4831 class BMPString(CommonString):
4833 tag_default = tag_encode(30)
4834 encoding = "utf-16-be"
4835 asn1_type_name = "BMPString"
4838 ChoiceState = namedtuple(
4840 BasicState._fields + ("specs", "value",),
4846 """``CHOICE`` special type
4850 class GeneralName(Choice):
4852 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4853 ("dNSName", IA5String(impl=tag_ctxp(2))),
4856 >>> gn = GeneralName()
4858 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4859 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4860 >>> gn["dNSName"] = IA5String("bar.baz")
4861 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4862 >>> gn["rfc822Name"]
4865 [2] IA5String IA5 bar.baz
4868 >>> gn.value == gn["dNSName"]
4871 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4873 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4874 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4876 __slots__ = ("specs",)
4878 asn1_type_name = "CHOICE"
4891 :param value: set the value. Either ``(choice, value)`` tuple, or
4892 :py:class:`pyderasn.Choice` object
4893 :param bytes impl: can not be set, do **not** use it
4894 :param bytes expl: override default tag with ``EXPLICIT`` one
4895 :param default: set default value. Type same as in ``value``
4896 :param bool optional: is object ``OPTIONAL`` in sequence
4898 if impl is not None:
4899 raise ValueError("no implicit tag allowed for CHOICE")
4900 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4902 schema = getattr(self, "schema", ())
4903 if len(schema) == 0:
4904 raise ValueError("schema must be specified")
4906 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
4909 if value is not None:
4910 self._value = self._value_sanitize(value)
4911 if default is not None:
4912 default_value = self._value_sanitize(default)
4913 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4914 default_obj.specs = self.specs
4915 default_obj._value = default_value
4916 self.default = default_obj
4918 self._value = copy(default_obj._value)
4919 if self._expl is not None:
4920 tag_class, _, tag_num = tag_decode(self._expl)
4921 self._tag_order = (tag_class, tag_num)
4923 def _value_sanitize(self, value):
4924 if (value.__class__ == tuple) and len(value) == 2:
4926 spec = self.specs.get(choice)
4928 raise ObjUnknown(choice)
4929 if not isinstance(obj, spec.__class__):
4930 raise InvalidValueType((spec,))
4931 return (choice, spec(obj))
4932 if isinstance(value, self.__class__):
4934 raise InvalidValueType((self.__class__, tuple))
4938 return self._value is not None and self._value[1].ready
4942 return self.expl_lenindef or (
4943 (self._value is not None) and
4944 self._value[1].bered
4947 def __getstate__(self):
4965 def __setstate__(self, state):
4966 super(Choice, self).__setstate__(state)
4967 self.specs = state.specs
4968 self._value = state.value
4970 def __eq__(self, their):
4971 if (their.__class__ == tuple) and len(their) == 2:
4972 return self._value == their
4973 if not isinstance(their, self.__class__):
4976 self.specs == their.specs and
4977 self._value == their._value
4987 return self.__class__(
4990 expl=self._expl if expl is None else expl,
4991 default=self.default if default is None else default,
4992 optional=self.optional if optional is None else optional,
4997 """Name of the choice
4999 self._assert_ready()
5000 return self._value[0]
5004 """Value of underlying choice
5006 self._assert_ready()
5007 return self._value[1]
5010 def tag_order(self):
5011 self._assert_ready()
5012 return self._value[1].tag_order if self._tag_order is None else self._tag_order
5015 def tag_order_cer(self):
5016 return min(v.tag_order_cer for v in itervalues(self.specs))
5018 def __getitem__(self, key):
5019 if key not in self.specs:
5020 raise ObjUnknown(key)
5021 if self._value is None:
5023 choice, value = self._value
5028 def __setitem__(self, key, value):
5029 spec = self.specs.get(key)
5031 raise ObjUnknown(key)
5032 if not isinstance(value, spec.__class__):
5033 raise InvalidValueType((spec.__class__,))
5034 self._value = (key, spec(value))
5042 return self._value[1].decoded if self.ready else False
5045 self._assert_ready()
5046 return self._value[1].encode()
5048 def _encode_cer(self, writer):
5049 self._assert_ready()
5050 self._value[1].encode_cer(writer)
5052 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5053 for choice, spec in iteritems(self.specs):
5054 sub_decode_path = decode_path + (choice,)
5060 decode_path=sub_decode_path,
5063 _ctx_immutable=False,
5070 klass=self.__class__,
5071 decode_path=decode_path,
5074 if tag_only: # pragma: no cover
5078 for _decode_path, value, tail in spec.decode_evgen(
5082 decode_path=sub_decode_path,
5084 _ctx_immutable=False,
5086 yield _decode_path, value, tail
5088 _, value, tail = next(spec.decode_evgen(
5092 decode_path=sub_decode_path,
5094 _ctx_immutable=False,
5097 obj = self.__class__(
5100 default=self.default,
5101 optional=self.optional,
5102 _decoded=(offset, 0, value.fulllen),
5104 obj._value = (choice, value)
5105 yield decode_path, obj, tail
5108 value = pp_console_row(next(self.pps()))
5110 value = "%s[%r]" % (value, self.value)
5113 def pps(self, decode_path=()):
5116 asn1_type_name=self.asn1_type_name,
5117 obj_name=self.__class__.__name__,
5118 decode_path=decode_path,
5119 value=self.choice if self.ready else None,
5120 optional=self.optional,
5121 default=self == self.default,
5122 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5123 expl=None if self._expl is None else tag_decode(self._expl),
5128 expl_lenindef=self.expl_lenindef,
5132 yield self.value.pps(decode_path=decode_path + (self.choice,))
5133 for pp in self.pps_lenindef(decode_path):
5137 class PrimitiveTypes(Choice):
5138 """Predefined ``CHOICE`` for all generic primitive types
5140 It could be useful for general decoding of some unspecified values:
5142 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
5143 OCTET STRING 3 bytes 666f6f
5144 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
5148 schema = tuple((klass.__name__, klass()) for klass in (
5172 AnyState = namedtuple(
5174 BasicState._fields + ("value", "defined"),
5180 """``ANY`` special type
5182 >>> Any(Integer(-123))
5183 ANY INTEGER -123 (0X:7B)
5184 >>> a = Any(OctetString(b"hello world").encode())
5185 ANY 040b68656c6c6f20776f726c64
5186 >>> hexenc(bytes(a))
5187 b'0x040x0bhello world'
5189 __slots__ = ("defined",)
5190 tag_default = tag_encode(0)
5191 asn1_type_name = "ANY"
5201 :param value: set the value. Either any kind of pyderasn's
5202 **ready** object, or bytes. Pay attention that
5203 **no** validation is performed if raw binary value
5204 is valid TLV, except just tag decoding
5205 :param bytes expl: override default tag with ``EXPLICIT`` one
5206 :param bool optional: is object ``OPTIONAL`` in sequence
5208 super(Any, self).__init__(None, expl, None, optional, _decoded)
5212 value = self._value_sanitize(value)
5214 if self._expl is None:
5215 if value.__class__ == binary_type:
5216 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5218 tag_class, tag_num = value.tag_order
5220 tag_class, _, tag_num = tag_decode(self._expl)
5221 self._tag_order = (tag_class, tag_num)
5224 def _value_sanitize(self, value):
5225 if value.__class__ == binary_type:
5227 raise ValueError("Any value can not be empty")
5229 if isinstance(value, self.__class__):
5231 if not isinstance(value, Obj):
5232 raise InvalidValueType((self.__class__, Obj, binary_type))
5237 return self._value is not None
5240 def tag_order(self):
5241 self._assert_ready()
5242 return self._tag_order
5246 if self.expl_lenindef or self.lenindef:
5248 if self.defined is None:
5250 return self.defined[1].bered
5252 def __getstate__(self):
5270 def __setstate__(self, state):
5271 super(Any, self).__setstate__(state)
5272 self._value = state.value
5273 self.defined = state.defined
5275 def __eq__(self, their):
5276 if their.__class__ == binary_type:
5277 if self._value.__class__ == binary_type:
5278 return self._value == their
5279 return self._value.encode() == their
5280 if issubclass(their.__class__, Any):
5281 if self.ready and their.ready:
5282 return bytes(self) == bytes(their)
5283 return self.ready == their.ready
5292 return self.__class__(
5294 expl=self._expl if expl is None else expl,
5295 optional=self.optional if optional is None else optional,
5298 def __bytes__(self):
5299 self._assert_ready()
5301 if value.__class__ == binary_type:
5303 return self._value.encode()
5310 self._assert_ready()
5312 if value.__class__ == binary_type:
5314 return value.encode()
5316 def _encode_cer(self, writer):
5317 self._assert_ready()
5319 if value.__class__ == binary_type:
5320 write_full(writer, value)
5322 value.encode_cer(writer)
5324 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5326 t, tlen, lv = tag_strip(tlv)
5327 except DecodeError as err:
5328 raise err.__class__(
5330 klass=self.__class__,
5331 decode_path=decode_path,
5335 l, llen, v = len_decode(lv)
5336 except LenIndefForm as err:
5337 if not ctx.get("bered", False):
5338 raise err.__class__(
5340 klass=self.__class__,
5341 decode_path=decode_path,
5344 llen, vlen, v = 1, 0, lv[1:]
5345 sub_offset = offset + tlen + llen
5347 while v[:EOC_LEN].tobytes() != EOC:
5348 chunk, v = Any().decode(
5351 decode_path=decode_path + (str(chunk_i),),
5354 _ctx_immutable=False,
5356 vlen += chunk.tlvlen
5357 sub_offset += chunk.tlvlen
5359 tlvlen = tlen + llen + vlen + EOC_LEN
5360 obj = self.__class__(
5361 value=None if evgen_mode else tlv[:tlvlen].tobytes(),
5363 optional=self.optional,
5364 _decoded=(offset, 0, tlvlen),
5367 obj.tag = t.tobytes()
5368 yield decode_path, obj, v[EOC_LEN:]
5370 except DecodeError as err:
5371 raise err.__class__(
5373 klass=self.__class__,
5374 decode_path=decode_path,
5378 raise NotEnoughData(
5379 "encoded length is longer than data",
5380 klass=self.__class__,
5381 decode_path=decode_path,
5384 tlvlen = tlen + llen + l
5385 v, tail = tlv[:tlvlen], v[l:]
5386 obj = self.__class__(
5387 value=None if evgen_mode else v.tobytes(),
5389 optional=self.optional,
5390 _decoded=(offset, 0, tlvlen),
5392 obj.tag = t.tobytes()
5393 yield decode_path, obj, tail
5396 return pp_console_row(next(self.pps()))
5398 def pps(self, decode_path=()):
5402 elif value.__class__ == binary_type:
5408 asn1_type_name=self.asn1_type_name,
5409 obj_name=self.__class__.__name__,
5410 decode_path=decode_path,
5412 blob=self._value if self._value.__class__ == binary_type else None,
5413 optional=self.optional,
5414 default=self == self.default,
5415 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5416 expl=None if self._expl is None else tag_decode(self._expl),
5421 expl_offset=self.expl_offset if self.expled else None,
5422 expl_tlen=self.expl_tlen if self.expled else None,
5423 expl_llen=self.expl_llen if self.expled else None,
5424 expl_vlen=self.expl_vlen if self.expled else None,
5425 expl_lenindef=self.expl_lenindef,
5426 lenindef=self.lenindef,
5429 defined_by, defined = self.defined or (None, None)
5430 if defined_by is not None:
5432 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5434 for pp in self.pps_lenindef(decode_path):
5438 ########################################################################
5439 # ASN.1 constructed types
5440 ########################################################################
5442 def get_def_by_path(defines_by_path, sub_decode_path):
5443 """Get define by decode path
5445 for path, define in defines_by_path:
5446 if len(path) != len(sub_decode_path):
5448 for p1, p2 in zip(path, sub_decode_path):
5449 if (not p1 is any) and (p1 != p2):
5455 def abs_decode_path(decode_path, rel_path):
5456 """Create an absolute decode path from current and relative ones
5458 :param decode_path: current decode path, starting point. Tuple of strings
5459 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5460 If first tuple's element is "/", then treat it as
5461 an absolute path, ignoring ``decode_path`` as
5462 starting point. Also this tuple can contain ".."
5463 elements, stripping the leading element from
5466 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5467 ("foo", "bar", "baz", "whatever")
5468 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5470 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5473 if rel_path[0] == "/":
5475 if rel_path[0] == "..":
5476 return abs_decode_path(decode_path[:-1], rel_path[1:])
5477 return decode_path + rel_path
5480 SequenceState = namedtuple(
5482 BasicState._fields + ("specs", "value",),
5487 class Sequence(Obj):
5488 """``SEQUENCE`` structure type
5490 You have to make specification of sequence::
5492 class Extension(Sequence):
5494 ("extnID", ObjectIdentifier()),
5495 ("critical", Boolean(default=False)),
5496 ("extnValue", OctetString()),
5499 Then, you can work with it as with dictionary.
5501 >>> ext = Extension()
5502 >>> Extension().specs
5504 ('extnID', OBJECT IDENTIFIER),
5505 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5506 ('extnValue', OCTET STRING),
5508 >>> ext["extnID"] = "1.2.3"
5509 Traceback (most recent call last):
5510 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5511 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5513 You can determine if sequence is ready to be encoded:
5518 Traceback (most recent call last):
5519 pyderasn.ObjNotReady: object is not ready: extnValue
5520 >>> ext["extnValue"] = OctetString(b"foobar")
5524 Value you want to assign, must have the same **type** as in
5525 corresponding specification, but it can have different tags,
5526 optional/default attributes -- they will be taken from specification
5529 class TBSCertificate(Sequence):
5531 ("version", Version(expl=tag_ctxc(0), default="v1")),
5534 >>> tbs = TBSCertificate()
5535 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5537 Assign ``None`` to remove value from sequence.
5539 You can set values in Sequence during its initialization:
5541 >>> AlgorithmIdentifier((
5542 ("algorithm", ObjectIdentifier("1.2.3")),
5543 ("parameters", Any(Null()))
5545 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5547 You can determine if value exists/set in the sequence and take its value:
5549 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5552 OBJECT IDENTIFIER 1.2.3
5554 But pay attention that if value has default, then it won't be (not
5555 in) in the sequence (because ``DEFAULT`` must not be encoded in
5556 DER), but you can read its value:
5558 >>> "critical" in ext, ext["critical"]
5559 (False, BOOLEAN False)
5560 >>> ext["critical"] = Boolean(True)
5561 >>> "critical" in ext, ext["critical"]
5562 (True, BOOLEAN True)
5564 All defaulted values are always optional.
5566 .. _allow_default_values_ctx:
5568 DER prohibits default value encoding and will raise an error if
5569 default value is unexpectedly met during decode.
5570 If :ref:`bered <bered_ctx>` context option is set, then no error
5571 will be raised, but ``bered`` attribute set. You can disable strict
5572 defaulted values existence validation by setting
5573 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5577 Check for default value existence is not performed in
5578 ``evgen_mode``, because previously decoded values are not stored
5579 in memory, to be able to compare them.
5581 Two sequences are equal if they have equal specification (schema),
5582 implicit/explicit tagging and the same values.
5584 __slots__ = ("specs",)
5585 tag_default = tag_encode(form=TagFormConstructed, num=16)
5586 asn1_type_name = "SEQUENCE"
5598 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5600 schema = getattr(self, "schema", ())
5602 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
5605 if value is not None:
5606 if issubclass(value.__class__, Sequence):
5607 self._value = value._value
5608 elif hasattr(value, "__iter__"):
5609 for seq_key, seq_value in value:
5610 self[seq_key] = seq_value
5612 raise InvalidValueType((Sequence,))
5613 if default is not None:
5614 if not issubclass(default.__class__, Sequence):
5615 raise InvalidValueType((Sequence,))
5616 default_value = default._value
5617 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5618 default_obj.specs = self.specs
5619 default_obj._value = default_value
5620 self.default = default_obj
5622 self._value = copy(default_obj._value)
5626 for name, spec in iteritems(self.specs):
5627 value = self._value.get(name)
5638 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5640 return any(value.bered for value in itervalues(self._value))
5642 def __getstate__(self):
5643 return SequenceState(
5657 {k: copy(v) for k, v in iteritems(self._value)},
5660 def __setstate__(self, state):
5661 super(Sequence, self).__setstate__(state)
5662 self.specs = state.specs
5663 self._value = state.value
5665 def __eq__(self, their):
5666 if not isinstance(their, self.__class__):
5669 self.specs == their.specs and
5670 self.tag == their.tag and
5671 self._expl == their._expl and
5672 self._value == their._value
5683 return self.__class__(
5686 impl=self.tag if impl is None else impl,
5687 expl=self._expl if expl is None else expl,
5688 default=self.default if default is None else default,
5689 optional=self.optional if optional is None else optional,
5692 def __contains__(self, key):
5693 return key in self._value
5695 def __setitem__(self, key, value):
5696 spec = self.specs.get(key)
5698 raise ObjUnknown(key)
5700 self._value.pop(key, None)
5702 if not isinstance(value, spec.__class__):
5703 raise InvalidValueType((spec.__class__,))
5704 value = spec(value=value)
5705 if spec.default is not None and value == spec.default:
5706 self._value.pop(key, None)
5708 self._value[key] = value
5710 def __getitem__(self, key):
5711 value = self._value.get(key)
5712 if value is not None:
5714 spec = self.specs.get(key)
5716 raise ObjUnknown(key)
5717 if spec.default is not None:
5721 def _values_for_encoding(self):
5722 for name, spec in iteritems(self.specs):
5723 value = self._value.get(name)
5727 raise ObjNotReady(name)
5731 v = b"".join(v.encode() for v in self._values_for_encoding())
5732 return b"".join((self.tag, len_encode(len(v)), v))
5734 def _encode_cer(self, writer):
5735 write_full(writer, self.tag + LENINDEF)
5736 for v in self._values_for_encoding():
5737 v.encode_cer(writer)
5738 write_full(writer, EOC)
5740 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5742 t, tlen, lv = tag_strip(tlv)
5743 except DecodeError as err:
5744 raise err.__class__(
5746 klass=self.__class__,
5747 decode_path=decode_path,
5752 klass=self.__class__,
5753 decode_path=decode_path,
5756 if tag_only: # pragma: no cover
5760 ctx_bered = ctx.get("bered", False)
5762 l, llen, v = len_decode(lv)
5763 except LenIndefForm as err:
5765 raise err.__class__(
5767 klass=self.__class__,
5768 decode_path=decode_path,
5771 l, llen, v = 0, 1, lv[1:]
5773 except DecodeError as err:
5774 raise err.__class__(
5776 klass=self.__class__,
5777 decode_path=decode_path,
5781 raise NotEnoughData(
5782 "encoded length is longer than data",
5783 klass=self.__class__,
5784 decode_path=decode_path,
5788 v, tail = v[:l], v[l:]
5790 sub_offset = offset + tlen + llen
5793 ctx_allow_default_values = ctx.get("allow_default_values", False)
5794 for name, spec in iteritems(self.specs):
5795 if spec.optional and (
5796 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5800 sub_decode_path = decode_path + (name,)
5803 for _decode_path, value, v_tail in spec.decode_evgen(
5807 decode_path=sub_decode_path,
5809 _ctx_immutable=False,
5811 yield _decode_path, value, v_tail
5813 _, value, v_tail = next(spec.decode_evgen(
5817 decode_path=sub_decode_path,
5819 _ctx_immutable=False,
5822 except TagMismatch as err:
5823 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5827 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5828 if not evgen_mode and defined is not None:
5829 defined_by, defined_spec = defined
5830 if issubclass(value.__class__, SequenceOf):
5831 for i, _value in enumerate(value):
5832 sub_sub_decode_path = sub_decode_path + (
5834 DecodePathDefBy(defined_by),
5836 defined_value, defined_tail = defined_spec.decode(
5837 memoryview(bytes(_value)),
5839 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5840 if value.expled else (value.tlen + value.llen)
5843 decode_path=sub_sub_decode_path,
5845 _ctx_immutable=False,
5847 if len(defined_tail) > 0:
5850 klass=self.__class__,
5851 decode_path=sub_sub_decode_path,
5854 _value.defined = (defined_by, defined_value)
5856 defined_value, defined_tail = defined_spec.decode(
5857 memoryview(bytes(value)),
5859 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5860 if value.expled else (value.tlen + value.llen)
5863 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5865 _ctx_immutable=False,
5867 if len(defined_tail) > 0:
5870 klass=self.__class__,
5871 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5874 value.defined = (defined_by, defined_value)
5876 value_len = value.fulllen
5878 sub_offset += value_len
5881 if spec.default is not None and value == spec.default:
5882 # This will not work in evgen_mode
5883 if ctx_bered or ctx_allow_default_values:
5887 "DEFAULT value met",
5888 klass=self.__class__,
5889 decode_path=sub_decode_path,
5892 values[name] = value
5893 spec_defines = getattr(spec, "defines", ())
5894 if len(spec_defines) == 0:
5895 defines_by_path = ctx.get("defines_by_path", ())
5896 if len(defines_by_path) > 0:
5897 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5898 if spec_defines is not None and len(spec_defines) > 0:
5899 for rel_path, schema in spec_defines:
5900 defined = schema.get(value, None)
5901 if defined is not None:
5902 ctx.setdefault("_defines", []).append((
5903 abs_decode_path(sub_decode_path[:-1], rel_path),
5907 if v[:EOC_LEN].tobytes() != EOC:
5910 klass=self.__class__,
5911 decode_path=decode_path,
5919 klass=self.__class__,
5920 decode_path=decode_path,
5923 obj = self.__class__(
5927 default=self.default,
5928 optional=self.optional,
5929 _decoded=(offset, llen, vlen),
5932 obj.lenindef = lenindef
5933 obj.ber_encoded = ber_encoded
5934 yield decode_path, obj, tail
5937 value = pp_console_row(next(self.pps()))
5939 for name in self.specs:
5940 _value = self._value.get(name)
5943 cols.append("%s: %s" % (name, repr(_value)))
5944 return "%s[%s]" % (value, "; ".join(cols))
5946 def pps(self, decode_path=()):
5949 asn1_type_name=self.asn1_type_name,
5950 obj_name=self.__class__.__name__,
5951 decode_path=decode_path,
5952 optional=self.optional,
5953 default=self == self.default,
5954 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5955 expl=None if self._expl is None else tag_decode(self._expl),
5960 expl_offset=self.expl_offset if self.expled else None,
5961 expl_tlen=self.expl_tlen if self.expled else None,
5962 expl_llen=self.expl_llen if self.expled else None,
5963 expl_vlen=self.expl_vlen if self.expled else None,
5964 expl_lenindef=self.expl_lenindef,
5965 lenindef=self.lenindef,
5966 ber_encoded=self.ber_encoded,
5969 for name in self.specs:
5970 value = self._value.get(name)
5973 yield value.pps(decode_path=decode_path + (name,))
5974 for pp in self.pps_lenindef(decode_path):
5978 class Set(Sequence):
5979 """``SET`` structure type
5981 Its usage is identical to :py:class:`pyderasn.Sequence`.
5983 .. _allow_unordered_set_ctx:
5985 DER prohibits unordered values encoding and will raise an error
5986 during decode. If :ref:`bered <bered_ctx>` context option is set,
5987 then no error will occur. Also you can disable strict values
5988 ordering check by setting ``"allow_unordered_set": True``
5989 :ref:`context <ctx>` option.
5992 tag_default = tag_encode(form=TagFormConstructed, num=17)
5993 asn1_type_name = "SET"
5996 v = b"".join(value.encode() for value in sorted(
5997 self._values_for_encoding(),
5998 key=attrgetter("tag_order"),
6000 return b"".join((self.tag, len_encode(len(v)), v))
6002 def _encode_cer(self, writer):
6003 write_full(writer, self.tag + LENINDEF)
6005 self._values_for_encoding(),
6006 key=attrgetter("tag_order_cer"),
6008 v.encode_cer(writer)
6009 write_full(writer, EOC)
6011 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
6013 t, tlen, lv = tag_strip(tlv)
6014 except DecodeError as err:
6015 raise err.__class__(
6017 klass=self.__class__,
6018 decode_path=decode_path,
6023 klass=self.__class__,
6024 decode_path=decode_path,
6031 ctx_bered = ctx.get("bered", False)
6033 l, llen, v = len_decode(lv)
6034 except LenIndefForm as err:
6036 raise err.__class__(
6038 klass=self.__class__,
6039 decode_path=decode_path,
6042 l, llen, v = 0, 1, lv[1:]
6044 except DecodeError as err:
6045 raise err.__class__(
6047 klass=self.__class__,
6048 decode_path=decode_path,
6052 raise NotEnoughData(
6053 "encoded length is longer than data",
6054 klass=self.__class__,
6058 v, tail = v[:l], v[l:]
6060 sub_offset = offset + tlen + llen
6063 ctx_allow_default_values = ctx.get("allow_default_values", False)
6064 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6065 tag_order_prev = (0, 0)
6066 _specs_items = copy(self.specs)
6069 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6071 for name, spec in iteritems(_specs_items):
6072 sub_decode_path = decode_path + (name,)
6078 decode_path=sub_decode_path,
6081 _ctx_immutable=False,
6088 klass=self.__class__,
6089 decode_path=decode_path,
6093 for _decode_path, value, v_tail in spec.decode_evgen(
6097 decode_path=sub_decode_path,
6099 _ctx_immutable=False,
6101 yield _decode_path, value, v_tail
6103 _, value, v_tail = next(spec.decode_evgen(
6107 decode_path=sub_decode_path,
6109 _ctx_immutable=False,
6112 value_tag_order = value.tag_order
6113 value_len = value.fulllen
6114 if tag_order_prev >= value_tag_order:
6115 if ctx_bered or ctx_allow_unordered_set:
6119 "unordered " + self.asn1_type_name,
6120 klass=self.__class__,
6121 decode_path=sub_decode_path,
6124 if spec.default is None or value != spec.default:
6126 elif ctx_bered or ctx_allow_default_values:
6130 "DEFAULT value met",
6131 klass=self.__class__,
6132 decode_path=sub_decode_path,
6135 values[name] = value
6136 del _specs_items[name]
6137 tag_order_prev = value_tag_order
6138 sub_offset += value_len
6142 obj = self.__class__(
6146 default=self.default,
6147 optional=self.optional,
6148 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6151 if v[:EOC_LEN].tobytes() != EOC:
6154 klass=self.__class__,
6155 decode_path=decode_path,
6160 for name, spec in iteritems(self.specs):
6161 if name not in values and not spec.optional:
6163 "%s value is not ready" % name,
6164 klass=self.__class__,
6165 decode_path=decode_path,
6170 obj.ber_encoded = ber_encoded
6171 yield decode_path, obj, tail
6174 SequenceOfState = namedtuple(
6176 BasicState._fields + ("spec", "value", "bound_min", "bound_max"),
6181 class SequenceOf(Obj):
6182 """``SEQUENCE OF`` sequence type
6184 For that kind of type you must specify the object it will carry on
6185 (bounds are for example here, not required)::
6187 class Ints(SequenceOf):
6192 >>> ints.append(Integer(123))
6193 >>> ints.append(Integer(234))
6195 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
6196 >>> [int(i) for i in ints]
6198 >>> ints.append(Integer(345))
6199 Traceback (most recent call last):
6200 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
6203 >>> ints[1] = Integer(345)
6205 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
6207 Also you can initialize sequence with preinitialized values:
6209 >>> ints = Ints([Integer(123), Integer(234)])
6211 __slots__ = ("spec", "_bound_min", "_bound_max")
6212 tag_default = tag_encode(form=TagFormConstructed, num=16)
6213 asn1_type_name = "SEQUENCE OF"
6226 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
6228 schema = getattr(self, "schema", None)
6230 raise ValueError("schema must be specified")
6232 self._bound_min, self._bound_max = getattr(
6236 ) if bounds is None else bounds
6238 if value is not None:
6239 self._value = self._value_sanitize(value)
6240 if default is not None:
6241 default_value = self._value_sanitize(default)
6242 default_obj = self.__class__(
6247 default_obj._value = default_value
6248 self.default = default_obj
6250 self._value = copy(default_obj._value)
6252 def _value_sanitize(self, value):
6253 if issubclass(value.__class__, SequenceOf):
6254 value = value._value
6255 elif hasattr(value, "__iter__"):
6258 raise InvalidValueType((self.__class__, iter))
6259 if not self._bound_min <= len(value) <= self._bound_max:
6260 raise BoundsError(self._bound_min, len(value), self._bound_max)
6262 if not isinstance(v, self.spec.__class__):
6263 raise InvalidValueType((self.spec.__class__,))
6268 return all(v.ready for v in self._value)
6272 if self.expl_lenindef or self.lenindef or self.ber_encoded:
6274 return any(v.bered for v in self._value)
6276 def __getstate__(self):
6277 return SequenceOfState(
6291 [copy(v) for v in self._value],
6296 def __setstate__(self, state):
6297 super(SequenceOf, self).__setstate__(state)
6298 self.spec = state.spec
6299 self._value = state.value
6300 self._bound_min = state.bound_min
6301 self._bound_max = state.bound_max
6303 def __eq__(self, their):
6304 if isinstance(their, self.__class__):
6306 self.spec == their.spec and
6307 self.tag == their.tag and
6308 self._expl == their._expl and
6309 self._value == their._value
6311 if hasattr(their, "__iter__"):
6312 return self._value == list(their)
6324 return self.__class__(
6328 (self._bound_min, self._bound_max)
6329 if bounds is None else bounds
6331 impl=self.tag if impl is None else impl,
6332 expl=self._expl if expl is None else expl,
6333 default=self.default if default is None else default,
6334 optional=self.optional if optional is None else optional,
6337 def __contains__(self, key):
6338 return key in self._value
6340 def append(self, value):
6341 if not isinstance(value, self.spec.__class__):
6342 raise InvalidValueType((self.spec.__class__,))
6343 if len(self._value) + 1 > self._bound_max:
6346 len(self._value) + 1,
6349 self._value.append(value)
6352 self._assert_ready()
6353 return iter(self._value)
6356 self._assert_ready()
6357 return len(self._value)
6359 def __setitem__(self, key, value):
6360 if not isinstance(value, self.spec.__class__):
6361 raise InvalidValueType((self.spec.__class__,))
6362 self._value[key] = self.spec(value=value)
6364 def __getitem__(self, key):
6365 return self._value[key]
6367 def _values_for_encoding(self):
6368 return iter(self._value)
6371 v = b"".join(v.encode() for v in self._values_for_encoding())
6372 return b"".join((self.tag, len_encode(len(v)), v))
6374 def _encode_cer(self, writer):
6375 write_full(writer, self.tag + LENINDEF)
6376 for v in self._values_for_encoding():
6377 v.encode_cer(writer)
6378 write_full(writer, EOC)
6388 ordering_check=False,
6391 t, tlen, lv = tag_strip(tlv)
6392 except DecodeError as err:
6393 raise err.__class__(
6395 klass=self.__class__,
6396 decode_path=decode_path,
6401 klass=self.__class__,
6402 decode_path=decode_path,
6409 ctx_bered = ctx.get("bered", False)
6411 l, llen, v = len_decode(lv)
6412 except LenIndefForm as err:
6414 raise err.__class__(
6416 klass=self.__class__,
6417 decode_path=decode_path,
6420 l, llen, v = 0, 1, lv[1:]
6422 except DecodeError as err:
6423 raise err.__class__(
6425 klass=self.__class__,
6426 decode_path=decode_path,
6430 raise NotEnoughData(
6431 "encoded length is longer than data",
6432 klass=self.__class__,
6433 decode_path=decode_path,
6437 v, tail = v[:l], v[l:]
6439 sub_offset = offset + tlen + llen
6442 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6443 value_prev = memoryview(v[:0])
6447 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6449 sub_decode_path = decode_path + (str(_value_count),)
6451 for _decode_path, value, v_tail in spec.decode_evgen(
6455 decode_path=sub_decode_path,
6457 _ctx_immutable=False,
6459 yield _decode_path, value, v_tail
6461 _, value, v_tail = next(spec.decode_evgen(
6465 decode_path=sub_decode_path,
6467 _ctx_immutable=False,
6470 value_len = value.fulllen
6472 if value_prev.tobytes() > v[:value_len].tobytes():
6473 if ctx_bered or ctx_allow_unordered_set:
6477 "unordered " + self.asn1_type_name,
6478 klass=self.__class__,
6479 decode_path=sub_decode_path,
6482 value_prev = v[:value_len]
6485 _value.append(value)
6486 sub_offset += value_len
6489 if evgen_mode and not self._bound_min <= _value_count <= self._bound_max:
6491 msg=str(BoundsError(self._bound_min, _value_count, self._bound_max)),
6492 klass=self.__class__,
6493 decode_path=decode_path,
6497 obj = self.__class__(
6498 value=None if evgen_mode else _value,
6500 bounds=(self._bound_min, self._bound_max),
6503 default=self.default,
6504 optional=self.optional,
6505 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6507 except BoundsError as err:
6510 klass=self.__class__,
6511 decode_path=decode_path,
6515 if v[:EOC_LEN].tobytes() != EOC:
6518 klass=self.__class__,
6519 decode_path=decode_path,
6524 obj.ber_encoded = ber_encoded
6525 yield decode_path, obj, tail
6529 pp_console_row(next(self.pps())),
6530 ", ".join(repr(v) for v in self._value),
6533 def pps(self, decode_path=()):
6536 asn1_type_name=self.asn1_type_name,
6537 obj_name=self.__class__.__name__,
6538 decode_path=decode_path,
6539 optional=self.optional,
6540 default=self == self.default,
6541 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6542 expl=None if self._expl is None else tag_decode(self._expl),
6547 expl_offset=self.expl_offset if self.expled else None,
6548 expl_tlen=self.expl_tlen if self.expled else None,
6549 expl_llen=self.expl_llen if self.expled else None,
6550 expl_vlen=self.expl_vlen if self.expled else None,
6551 expl_lenindef=self.expl_lenindef,
6552 lenindef=self.lenindef,
6553 ber_encoded=self.ber_encoded,
6556 for i, value in enumerate(self._value):
6557 yield value.pps(decode_path=decode_path + (str(i),))
6558 for pp in self.pps_lenindef(decode_path):
6562 class SetOf(SequenceOf):
6563 """``SET OF`` sequence type
6565 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6568 tag_default = tag_encode(form=TagFormConstructed, num=17)
6569 asn1_type_name = "SET OF"
6572 v = b"".join(sorted(v.encode() for v in self._values_for_encoding()))
6573 return b"".join((self.tag, len_encode(len(v)), v))
6575 def _encode_cer(self, writer):
6576 write_full(writer, self.tag + LENINDEF)
6577 for v in sorted(encode_cer(v) for v in self._values_for_encoding()):
6578 write_full(writer, v)
6579 write_full(writer, EOC)
6581 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
6582 return super(SetOf, self)._decode(
6589 ordering_check=True,
6593 def obj_by_path(pypath): # pragma: no cover
6594 """Import object specified as string Python path
6596 Modules must be separated from classes/functions with ``:``.
6598 >>> obj_by_path("foo.bar:Baz")
6599 <class 'foo.bar.Baz'>
6600 >>> obj_by_path("foo.bar:Baz.boo")
6601 <classmethod 'foo.bar.Baz.boo'>
6603 mod, objs = pypath.rsplit(":", 1)
6604 from importlib import import_module
6605 obj = import_module(mod)
6606 for obj_name in objs.split("."):
6607 obj = getattr(obj, obj_name)
6611 def generic_decoder(): # pragma: no cover
6612 # All of this below is a big hack with self references
6613 choice = PrimitiveTypes()
6614 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6615 choice.specs["SetOf"] = SetOf(schema=choice)
6616 for i in six_xrange(31):
6617 choice.specs["SequenceOf%d" % i] = SequenceOf(
6621 choice.specs["Any"] = Any()
6623 # Class name equals to type name, to omit it from output
6624 class SEQUENCEOF(SequenceOf):
6632 with_decode_path=False,
6633 decode_path_only=(),
6635 def _pprint_pps(pps):
6637 if hasattr(pp, "_fields"):
6639 decode_path_only != () and
6640 pp.decode_path[:len(decode_path_only)] != decode_path_only
6643 if pp.asn1_type_name == Choice.asn1_type_name:
6645 pp_kwargs = pp._asdict()
6646 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6647 pp = _pp(**pp_kwargs)
6648 yield pp_console_row(
6653 with_colours=with_colours,
6654 with_decode_path=with_decode_path,
6655 decode_path_len_decrease=len(decode_path_only),
6657 for row in pp_console_blob(
6659 decode_path_len_decrease=len(decode_path_only),
6663 for row in _pprint_pps(pp):
6665 return "\n".join(_pprint_pps(obj.pps()))
6666 return SEQUENCEOF(), pprint_any
6669 def main(): # pragma: no cover
6671 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6672 parser.add_argument(
6676 help="Skip that number of bytes from the beginning",
6678 parser.add_argument(
6680 help="Python paths to dictionary with OIDs, comma separated",
6682 parser.add_argument(
6684 help="Python path to schema definition to use",
6686 parser.add_argument(
6687 "--defines-by-path",
6688 help="Python path to decoder's defines_by_path",
6690 parser.add_argument(
6692 action="store_true",
6693 help="Disallow BER encoding",
6695 parser.add_argument(
6696 "--print-decode-path",
6697 action="store_true",
6698 help="Print decode paths",
6700 parser.add_argument(
6701 "--decode-path-only",
6702 help="Print only specified decode path",
6704 parser.add_argument(
6706 action="store_true",
6707 help="Allow explicit tag out-of-bound",
6709 parser.add_argument(
6711 type=argparse.FileType("rb"),
6712 help="Path to BER/CER/DER file you want to decode",
6714 args = parser.parse_args()
6716 args.RAWFile.seek(args.skip)
6717 raw = memoryview(args.RAWFile.read())
6718 args.RAWFile.close()
6720 raw = file_mmaped(args.RAWFile)[args.skip:]
6722 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6723 if args.oids else ()
6726 schema = obj_by_path(args.schema)
6727 from functools import partial
6728 pprinter = partial(pprint, big_blobs=True)
6730 schema, pprinter = generic_decoder()
6732 "bered": not args.nobered,
6733 "allow_expl_oob": args.allow_expl_oob,
6735 if args.defines_by_path is not None:
6736 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6737 obj, tail = schema().decode(raw, ctx=ctx)
6738 from os import environ
6742 with_colours=environ.get("NO_COLOR") is None,
6743 with_decode_path=args.print_decode_path,
6745 () if args.decode_path_only is None else
6746 tuple(args.decode_path_only.split(":"))
6750 print("\nTrailing data: %s" % hexenc(tail))
6753 if __name__ == "__main__":