3 # cython: language_level=3
4 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
5 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Lesser General Public License as
9 # published by the Free Software Foundation, version 3 of the License.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this program. If not, see <http://www.gnu.org/licenses/>.
18 """Python ASN.1 DER/BER codec with abstract structures
20 This library allows you to marshal various structures in ASN.1 DER
21 format, unmarshal them in BER/CER/DER ones.
25 >>> Integer().decod(raw) == i
28 There are primitive types, holding single values
29 (:py:class:`pyderasn.BitString`,
30 :py:class:`pyderasn.Boolean`,
31 :py:class:`pyderasn.Enumerated`,
32 :py:class:`pyderasn.GeneralizedTime`,
33 :py:class:`pyderasn.Integer`,
34 :py:class:`pyderasn.Null`,
35 :py:class:`pyderasn.ObjectIdentifier`,
36 :py:class:`pyderasn.OctetString`,
37 :py:class:`pyderasn.UTCTime`,
38 :py:class:`various strings <pyderasn.CommonString>`
39 (:py:class:`pyderasn.BMPString`,
40 :py:class:`pyderasn.GeneralString`,
41 :py:class:`pyderasn.GraphicString`,
42 :py:class:`pyderasn.IA5String`,
43 :py:class:`pyderasn.ISO646String`,
44 :py:class:`pyderasn.NumericString`,
45 :py:class:`pyderasn.PrintableString`,
46 :py:class:`pyderasn.T61String`,
47 :py:class:`pyderasn.TeletexString`,
48 :py:class:`pyderasn.UniversalString`,
49 :py:class:`pyderasn.UTF8String`,
50 :py:class:`pyderasn.VideotexString`,
51 :py:class:`pyderasn.VisibleString`)),
52 constructed types, holding multiple primitive types
53 (:py:class:`pyderasn.Sequence`,
54 :py:class:`pyderasn.SequenceOf`,
55 :py:class:`pyderasn.Set`,
56 :py:class:`pyderasn.SetOf`),
57 and special types like
58 :py:class:`pyderasn.Any` and
59 :py:class:`pyderasn.Choice`.
67 Most types in ASN.1 has specific tag for them. ``Obj.tag_default`` is
68 the default tag used during coding process. You can override it with
69 either ``IMPLICIT`` (using either ``impl`` keyword argument or ``impl``
70 class attribute), or ``EXPLICIT`` one (using either ``expl`` keyword
71 argument or ``expl`` class attribute). Both arguments take raw binary
72 string, containing that tag. You can **not** set implicit and explicit
75 There are :py:func:`pyderasn.tag_ctxp` and :py:func:`pyderasn.tag_ctxc`
76 functions, allowing you to easily create ``CONTEXT``
77 ``PRIMITIVE``/``CONSTRUCTED`` tags, by specifying only the required tag
82 EXPLICIT tags always have **constructed** tag. PyDERASN does not
83 explicitly check correctness of schema input here.
87 Implicit tags have **primitive** (``tag_ctxp``) encoding for
92 >>> Integer(impl=tag_ctxp(1))
94 >>> Integer(expl=tag_ctxc(2))
97 Implicit tag is not explicitly shown.
99 Two objects of the same type, but with different implicit/explicit tags
102 You can get object's effective tag (either default or implicited) through
103 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
106 >>> tag_decode(tag_ctxc(123))
108 >>> klass, form, num = tag_decode(tag_ctxc(123))
109 >>> klass == TagClassContext
111 >>> form == TagFormConstructed
114 To determine if object has explicit tag, use ``expled`` boolean property
115 and ``expl_tag`` property, returning explicit tag's value.
120 Many objects in sequences could be ``OPTIONAL`` and could have
121 ``DEFAULT`` value. You can specify that object's property using
122 corresponding keyword arguments.
124 >>> Integer(optional=True, default=123)
125 INTEGER 123 OPTIONAL DEFAULT
127 Those specifications do not play any role in primitive value encoding,
128 but are taken into account when dealing with sequences holding them. For
129 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
132 class Version(Integer):
138 class TBSCertificate(Sequence):
140 ("version", Version(expl=tag_ctxc(0), default="v1")),
143 When default argument is used and value is not specified, then it equals
151 Some objects give ability to set value size constraints. This is either
152 possible integer value, or allowed length of various strings and
153 sequences. Constraints are set in the following way::
158 And values satisfaction is checked as: ``MIN <= X <= MAX``.
160 For simplicity you can also set bounds the following way::
162 bounded_x = X(bounds=(MIN, MAX))
164 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
170 All objects have ``ready`` boolean property, that tells if object is
171 ready to be encoded. If that kind of action is performed on unready
172 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
174 All objects are friendly to ``copy.copy()`` and copied objects can be
177 Also all objects can be safely ``pickle``-d, but pay attention that
178 pickling among different PyDERASN versions is prohibited.
185 Decoding is performed using :py:meth:`pyderasn.Obj.decode` method.
186 ``offset`` optional argument could be used to set initial object's
187 offset in the binary data, for convenience. It returns decoded object
188 and remaining unmarshalled data (tail). Internally all work is done on
189 ``memoryview(data)``, and you can leave returning tail as a memoryview,
190 by specifying ``leavemm=True`` argument.
192 Also note convenient :py:meth:`pyderasn.Obj.decod` method, that
193 immediately checks and raises if there is non-empty tail.
195 When object is decoded, ``decoded`` property is true and you can safely
196 use following properties:
198 * ``offset`` -- position including initial offset where object's tag starts
199 * ``tlen`` -- length of object's tag
200 * ``llen`` -- length of object's length value
201 * ``vlen`` -- length of object's value
202 * ``tlvlen`` -- length of the whole object
204 Pay attention that those values do **not** include anything related to
205 explicit tag. If you want to know information about it, then use:
207 * ``expled`` -- to know if explicit tag is set
208 * ``expl_offset`` (it is lesser than ``offset``)
211 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
212 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
214 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
217 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
224 You can specify so called context keyword argument during
225 :py:meth:`pyderasn.Obj.decode` invocation. It is dictionary containing
226 various options governing decoding process.
228 Currently available context options:
230 * :ref:`allow_default_values <allow_default_values_ctx>`
231 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
232 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
233 * :ref:`bered <bered_ctx>`
234 * :ref:`defines_by_path <defines_by_path_ctx>`
241 All objects have ``pps()`` method, that is a generator of
242 :py:class:`pyderasn.PP` namedtuple, holding various raw information
243 about the object. If ``pps`` is called on sequences, then all underlying
244 ``PP`` will be yielded.
246 You can use :py:func:`pyderasn.pp_console_row` function, converting
247 those ``PP`` to human readable string. Actually exactly it is used for
248 all object ``repr``. But it is easy to write custom formatters.
250 >>> from pyderasn import pprint
251 >>> encoded = Integer(-12345).encode()
252 >>> obj, tail = Integer().decode(encoded)
253 >>> print(pprint(obj))
254 0 [1,1, 2] INTEGER -12345
258 Example certificate::
260 >>> print(pprint(crt))
261 0 [1,3,1604] Certificate SEQUENCE
262 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
263 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
264 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
265 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
266 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
267 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
269 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
270 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
271 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
272 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
273 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
274 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
275 . . . . . . . 13:02:45:53
277 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
278 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
279 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
281 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
282 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
283 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
288 Let's parse that output, human::
290 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
291 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
292 0 1 2 3 4 5 6 7 8 9 10 11
296 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
302 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
308 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
313 Offset of the object, where its DER/BER encoding begins.
314 Pay attention that it does **not** include explicit tag.
316 If explicit tag exists, then this is its length (tag + encoded length).
318 Length of object's tag. For example CHOICE does not have its own tag,
321 Length of encoded length.
323 Length of encoded value.
325 Visual indentation to show the depth of object in the hierarchy.
327 Object's name inside SEQUENCE/CHOICE.
329 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
330 here. "IMPLICIT" is omitted.
332 Object's class name, if set. Omitted if it is just an ordinary simple
333 value (like with ``algorithm`` in example above).
337 Object's value, if set. Can consist of multiple words (like OCTET/BIT
338 STRINGs above). We see ``v3`` value in Version, because it is named.
339 ``rdnSequence`` is the choice of CHOICE type.
341 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
342 default one, specified in the schema.
344 Shows does object contains any kind of BER encoded data (possibly
345 Sequence holding BER-encoded underlying value).
347 Only applicable to BER encoded data. Indefinite length encoding mark.
349 Only applicable to BER encoded data. If object has BER-specific
350 encoding, then ``BER`` will be shown. It does not depend on indefinite
351 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
352 (and its derivatives), ``SET``, ``SET OF``, ``UTCTime``, ``GeneralizedTime``
360 ASN.1 structures often have ANY and OCTET STRING fields, that are
361 DEFINED BY some previously met ObjectIdentifier. This library provides
362 ability to specify mapping between some OID and field that must be
363 decoded with specific specification.
370 :py:class:`pyderasn.ObjectIdentifier` field inside
371 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
372 necessary for decoding structures. For example, CMS (:rfc:`5652`)
375 class ContentInfo(Sequence):
377 ("contentType", ContentType(defines=((("content",), {
378 id_digestedData: DigestedData(),
379 id_signedData: SignedData(),
381 ("content", Any(expl=tag_ctxc(0))),
384 ``contentType`` field tells that it defines that ``content`` must be
385 decoded with ``SignedData`` specification, if ``contentType`` equals to
386 ``id-signedData``. The same applies to ``DigestedData``. If
387 ``contentType`` contains unknown OID, then no automatic decoding is
390 You can specify multiple fields, that will be autodecoded -- that is why
391 ``defines`` kwarg is a sequence. You can specify defined field
392 relatively or absolutely to current decode path. For example ``defines``
393 for AlgorithmIdentifier of X.509's
394 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
398 id_ecPublicKey: ECParameters(),
399 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
401 (("..", "subjectPublicKey"), {
402 id_rsaEncryption: RSAPublicKey(),
403 id_GostR3410_2001: OctetString(),
407 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
408 autodecode its parameters inside SPKI's algorithm and its public key
411 Following types can be automatically decoded (DEFINED BY):
413 * :py:class:`pyderasn.Any`
414 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
415 * :py:class:`pyderasn.OctetString`
416 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
417 ``Any``/``BitString``/``OctetString``-s
419 When any of those fields is automatically decoded, then ``.defined``
420 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
421 was defined, ``value`` contains corresponding decoded value. For example
422 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
424 .. _defines_by_path_ctx:
426 defines_by_path context option
427 ______________________________
429 Sometimes you either can not or do not want to explicitly set *defines*
430 in the schema. You can dynamically apply those definitions when calling
431 ``.decode()`` method.
433 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
434 value must be sequence of following tuples::
436 (decode_path, defines)
438 where ``decode_path`` is a tuple holding so-called decode path to the
439 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
440 ``defines``, holding exactly the same value as accepted in its
441 :ref:`keyword argument <defines>`.
443 For example, again for CMS, you want to automatically decode
444 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
445 structures it may hold. Also, automatically decode ``controlSequence``
448 content_info = ContentInfo().decod(data, ctx={"defines_by_path": (
451 ((("content",), {id_signedData: SignedData()}),),
456 DecodePathDefBy(id_signedData),
461 id_cct_PKIData: PKIData(),
462 id_cct_PKIResponse: PKIResponse(),
468 DecodePathDefBy(id_signedData),
471 DecodePathDefBy(id_cct_PKIResponse),
477 id_cmc_recipientNonce: RecipientNonce(),
478 id_cmc_senderNonce: SenderNonce(),
479 id_cmc_statusInfoV2: CMCStatusInfoV2(),
480 id_cmc_transactionId: TransactionId(),
485 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
486 First function is useful for path construction when some automatic
487 decoding is already done. ``any`` means literally any value it meet --
488 useful for SEQUENCE/SET OF-s.
495 By default PyDERASN accepts only DER encoded data. It always encodes to
496 DER. But you can optionally enable BER decoding with setting ``bered``
497 :ref:`context <ctx>` argument to True. Indefinite lengths and
498 constructed primitive types should be parsed successfully.
500 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
501 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
502 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``,
503 ``UTCTime``, ``GeneralizedTime`` can contain it.
504 * If object has an indefinite length encoding, then its ``lenindef``
505 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
506 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
508 * If object has an indefinite length encoded explicit tag, then
509 ``expl_lenindef`` is set to True.
510 * If object has either any of BER-related encoding (explicit tag
511 indefinite length, object's indefinite length, BER-encoding) or any
512 underlying component has that kind of encoding, then ``bered``
513 attribute is set to True. For example SignedData CMS can have
514 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
515 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
517 EOC (end-of-contents) token's length is taken in advance in object's
520 .. _allow_expl_oob_ctx:
522 Allow explicit tag out-of-bound
523 -------------------------------
525 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
526 one value, more than one object. If you set ``allow_expl_oob`` context
527 option to True, then no error will be raised and that invalid encoding
528 will be silently further processed. But pay attention that offsets and
529 lengths will be invalid in that case.
533 This option should be used only for skipping some decode errors, just
534 to see the decoded structure somehow.
538 .. autoclass:: pyderasn.Obj
546 .. autoclass:: pyderasn.Boolean
551 .. autoclass:: pyderasn.Integer
552 :members: __init__, named
556 .. autoclass:: pyderasn.BitString
557 :members: __init__, bit_len, named
561 .. autoclass:: pyderasn.OctetString
566 .. autoclass:: pyderasn.Null
571 .. autoclass:: pyderasn.ObjectIdentifier
576 .. autoclass:: pyderasn.Enumerated
580 .. autoclass:: pyderasn.CommonString
584 .. autoclass:: pyderasn.NumericString
588 .. autoclass:: pyderasn.PrintableString
589 :members: __init__, allow_asterisk, allow_ampersand
593 .. autoclass:: pyderasn.UTCTime
594 :members: __init__, todatetime
598 .. autoclass:: pyderasn.GeneralizedTime
599 :members: __init__, todatetime
606 .. autoclass:: pyderasn.Choice
607 :members: __init__, choice, value
611 .. autoclass:: PrimitiveTypes
615 .. autoclass:: pyderasn.Any
623 .. autoclass:: pyderasn.Sequence
628 .. autoclass:: pyderasn.Set
633 .. autoclass:: pyderasn.SequenceOf
638 .. autoclass:: pyderasn.SetOf
644 .. autofunction:: pyderasn.abs_decode_path
645 .. autofunction:: pyderasn.colonize_hex
646 .. autofunction:: pyderasn.encode_cer
647 .. autofunction:: pyderasn.file_mmaped
648 .. autofunction:: pyderasn.hexenc
649 .. autofunction:: pyderasn.hexdec
650 .. autofunction:: pyderasn.tag_encode
651 .. autofunction:: pyderasn.tag_decode
652 .. autofunction:: pyderasn.tag_ctxp
653 .. autofunction:: pyderasn.tag_ctxc
654 .. autoclass:: pyderasn.DecodeError
656 .. autoclass:: pyderasn.NotEnoughData
657 .. autoclass:: pyderasn.ExceedingData
658 .. autoclass:: pyderasn.LenIndefForm
659 .. autoclass:: pyderasn.TagMismatch
660 .. autoclass:: pyderasn.InvalidLength
661 .. autoclass:: pyderasn.InvalidOID
662 .. autoclass:: pyderasn.ObjUnknown
663 .. autoclass:: pyderasn.ObjNotReady
664 .. autoclass:: pyderasn.InvalidValueType
665 .. autoclass:: pyderasn.BoundsError
672 You can decode DER/BER files using command line abilities::
674 $ python -m pyderasn --schema tests.test_crts:Certificate path/to/file
676 If there is no schema for your file, then you can try parsing it without,
677 but of course IMPLICIT tags will often make it impossible. But result is
678 good enough for the certificate above::
680 $ python -m pyderasn path/to/file
681 0 [1,3,1604] . >: SEQUENCE OF
682 4 [1,3,1453] . . >: SEQUENCE OF
683 8 [0,0, 5] . . . . >: [0] ANY
684 . . . . . A0:03:02:01:02
685 13 [1,1, 3] . . . . >: INTEGER 61595
686 18 [1,1, 13] . . . . >: SEQUENCE OF
687 20 [1,1, 9] . . . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
688 31 [1,1, 0] . . . . . . >: NULL
689 33 [1,3, 274] . . . . >: SEQUENCE OF
690 37 [1,1, 11] . . . . . . >: SET OF
691 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
692 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER 2.5.4.6
693 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
695 1409 [1,1, 50] . . . . . . >: SEQUENCE OF
696 1411 [1,1, 8] . . . . . . . . >: OBJECT IDENTIFIER 1.3.6.1.5.5.7.1.1
697 1421 [1,1, 38] . . . . . . . . >: OCTET STRING 38 bytes
698 . . . . . . . . . 30:24:30:22:06:08:2B:06:01:05:05:07:30:01:86:16
699 . . . . . . . . . 68:74:74:70:3A:2F:2F:6F:63:73:70:2E:69:70:73:63
700 . . . . . . . . . 61:2E:63:6F:6D:2F
701 1461 [1,1, 13] . . >: SEQUENCE OF
702 1463 [1,1, 9] . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
703 1474 [1,1, 0] . . . . >: NULL
704 1476 [1,2, 129] . . >: BIT STRING 1024 bits
705 . . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
706 . . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
712 If you have got dictionaries with ObjectIdentifiers, like example one
713 from ``tests/test_crts.py``::
716 "1.2.840.113549.1.1.1": "id-rsaEncryption",
717 "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
719 "2.5.4.10": "id-at-organizationName",
720 "2.5.4.11": "id-at-organizationalUnitName",
723 then you can pass it to pretty printer to see human readable OIDs::
725 $ python -m pyderasn --oids tests.test_crts:stroid2name path/to/file
727 37 [1,1, 11] . . . . . . >: SET OF
728 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
729 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
730 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
731 50 [1,1, 18] . . . . . . >: SET OF
732 52 [1,1, 16] . . . . . . . . >: SEQUENCE OF
733 54 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
734 59 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
735 70 [1,1, 18] . . . . . . >: SET OF
736 72 [1,1, 16] . . . . . . . . >: SEQUENCE OF
737 74 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
738 79 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
744 Each decoded element has so-called decode path: sequence of structure
745 names it is passing during the decode process. Each element has its own
746 unique path inside the whole ASN.1 tree. You can print it out with
747 ``--print-decode-path`` option::
749 $ python -m pyderasn --schema path.to:Certificate --print-decode-path path/to/file
750 0 [1,3,1604] Certificate SEQUENCE []
751 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE [tbsCertificate]
752 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL [tbsCertificate:version]
753 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595 [tbsCertificate:serialNumber]
754 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE [tbsCertificate:signature]
755 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5 [tbsCertificate:signature:algorithm]
756 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL [tbsCertificate:signature:parameters]
758 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence [tbsCertificate:issuer]
759 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF [tbsCertificate:issuer:rdnSequence]
760 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF [tbsCertificate:issuer:rdnSequence:0]
761 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE [tbsCertificate:issuer:rdnSequence:0:0]
762 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6 [tbsCertificate:issuer:rdnSequence:0:0:type]
763 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY [tbsCertificate:issuer:rdnSequence:0:0:value]
764 . . . . . . . 13:02:45:53
765 46 [1,1, 2] . . . . . . . DEFINED BY 2.5.4.6: CountryName PrintableString ES [tbsCertificate:issuer:rdnSequence:0:0:value:DEFINED BY 2.5.4.6]
768 Now you can print only the specified tree, for example signature algorithm::
770 $ python -m pyderasn --schema path.to:Certificate --decode-path-only tbsCertificate:signature path/to/file
771 18 [1,1, 13] AlgorithmIdentifier SEQUENCE
772 20 [1,1, 9] . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
773 31 [0,0, 2] . parameters: [UNIV 5] ANY OPTIONAL
777 from codecs import getdecoder
778 from codecs import getencoder
779 from collections import namedtuple
780 from collections import OrderedDict
781 from copy import copy
782 from datetime import datetime
783 from datetime import timedelta
784 from io import BytesIO
785 from math import ceil
786 from mmap import mmap
787 from mmap import PROT_READ
788 from operator import attrgetter
789 from string import ascii_letters
790 from string import digits
791 from sys import version_info
792 from unicodedata import category as unicat
794 from six import add_metaclass
795 from six import binary_type
796 from six import byte2int
797 from six import indexbytes
798 from six import int2byte
799 from six import integer_types
800 from six import iterbytes
801 from six import iteritems
802 from six import itervalues
804 from six import string_types
805 from six import text_type
806 from six import unichr as six_unichr
807 from six.moves import xrange as six_xrange
811 from termcolor import colored
812 except ImportError: # pragma: no cover
813 def colored(what, *args, **kwargs):
862 "TagClassApplication",
866 "TagFormConstructed",
877 TagClassUniversal = 0
878 TagClassApplication = 1 << 6
879 TagClassContext = 1 << 7
880 TagClassPrivate = 1 << 6 | 1 << 7
882 TagFormConstructed = 1 << 5
885 TagClassApplication: "APPLICATION ",
886 TagClassPrivate: "PRIVATE ",
887 TagClassUniversal: "UNIV ",
891 LENINDEF = b"\x80" # length indefinite mark
892 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
893 NAMEDTUPLE_KWARGS = {} if version_info < (3, 6) else {"module": __name__}
894 SET01 = frozenset("01")
895 DECIMALS = frozenset(digits)
900 """Make mmap-ed memoryview for reading from file
902 :param fd: file object
903 :returns: memoryview over read-only mmap-ing of the whole file
905 return memoryview(mmap(fd.fileno(), 0, prot=PROT_READ))
908 if not set(value) <= DECIMALS:
909 raise ValueError("non-pure integer")
912 def fractions2float(fractions_raw):
913 pureint(fractions_raw)
914 return float("0." + fractions_raw)
917 def get_def_by_path(defines_by_path, sub_decode_path):
918 """Get define by decode path
920 for path, define in defines_by_path:
921 if len(path) != len(sub_decode_path):
923 for p1, p2 in zip(path, sub_decode_path):
924 if (not p1 is any) and (p1 != p2):
930 ########################################################################
932 ########################################################################
934 class ASN1Error(ValueError):
938 class DecodeError(ASN1Error):
939 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
941 :param str msg: reason of decode failing
942 :param klass: optional exact DecodeError inherited class (like
943 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
944 :py:exc:`InvalidLength`)
945 :param decode_path: tuple of strings. It contains human
946 readable names of the fields through which
947 decoding process has passed
948 :param int offset: binary offset where failure happened
950 super(DecodeError, self).__init__()
953 self.decode_path = decode_path
959 "" if self.klass is None else self.klass.__name__,
961 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
962 if len(self.decode_path) > 0 else ""
964 ("(at %d)" % self.offset) if self.offset > 0 else "",
970 return "%s(%s)" % (self.__class__.__name__, self)
973 class NotEnoughData(DecodeError):
977 class ExceedingData(ASN1Error):
978 def __init__(self, nbytes):
979 super(ExceedingData, self).__init__()
983 return "%d trailing bytes" % self.nbytes
986 return "%s(%s)" % (self.__class__.__name__, self)
989 class LenIndefForm(DecodeError):
993 class TagMismatch(DecodeError):
997 class InvalidLength(DecodeError):
1001 class InvalidOID(DecodeError):
1005 class ObjUnknown(ASN1Error):
1006 def __init__(self, name):
1007 super(ObjUnknown, self).__init__()
1011 return "object is unknown: %s" % self.name
1014 return "%s(%s)" % (self.__class__.__name__, self)
1017 class ObjNotReady(ASN1Error):
1018 def __init__(self, name):
1019 super(ObjNotReady, self).__init__()
1023 return "object is not ready: %s" % self.name
1026 return "%s(%s)" % (self.__class__.__name__, self)
1029 class InvalidValueType(ASN1Error):
1030 def __init__(self, expected_types):
1031 super(InvalidValueType, self).__init__()
1032 self.expected_types = expected_types
1035 return "invalid value type, expected: %s" % ", ".join(
1036 [repr(t) for t in self.expected_types]
1040 return "%s(%s)" % (self.__class__.__name__, self)
1043 class BoundsError(ASN1Error):
1044 def __init__(self, bound_min, value, bound_max):
1045 super(BoundsError, self).__init__()
1046 self.bound_min = bound_min
1048 self.bound_max = bound_max
1051 return "unsatisfied bounds: %s <= %s <= %s" % (
1058 return "%s(%s)" % (self.__class__.__name__, self)
1061 ########################################################################
1063 ########################################################################
1065 _hexdecoder = getdecoder("hex")
1066 _hexencoder = getencoder("hex")
1070 """Binary data to hexadecimal string convert
1072 return _hexdecoder(data)[0]
1076 """Hexadecimal string to binary data convert
1078 return _hexencoder(data)[0].decode("ascii")
1081 def int_bytes_len(num, byte_len=8):
1084 return int(ceil(float(num.bit_length()) / byte_len))
1087 def zero_ended_encode(num):
1088 octets = bytearray(int_bytes_len(num, 7))
1090 octets[i] = num & 0x7F
1094 octets[i] = 0x80 | (num & 0x7F)
1097 return bytes(octets)
1100 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
1101 """Encode tag to binary form
1103 :param int num: tag's number
1104 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
1105 :py:data:`pyderasn.TagClassContext`,
1106 :py:data:`pyderasn.TagClassApplication`,
1107 :py:data:`pyderasn.TagClassPrivate`)
1108 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
1109 :py:data:`pyderasn.TagFormConstructed`)
1113 return int2byte(klass | form | num)
1114 # [XX|X|11111][1.......][1.......] ... [0.......]
1115 return int2byte(klass | form | 31) + zero_ended_encode(num)
1118 def tag_decode(tag):
1119 """Decode tag from binary form
1123 No validation is performed, assuming that it has already passed.
1125 It returns tuple with three integers, as
1126 :py:func:`pyderasn.tag_encode` accepts.
1128 first_octet = byte2int(tag)
1129 klass = first_octet & 0xC0
1130 form = first_octet & 0x20
1131 if first_octet & 0x1F < 0x1F:
1132 return (klass, form, first_octet & 0x1F)
1134 for octet in iterbytes(tag[1:]):
1137 return (klass, form, num)
1141 """Create CONTEXT PRIMITIVE tag
1143 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
1147 """Create CONTEXT CONSTRUCTED tag
1149 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
1152 def tag_strip(data):
1153 """Take off tag from the data
1155 :returns: (encoded tag, tag length, remaining data)
1158 raise NotEnoughData("no data at all")
1159 if byte2int(data) & 0x1F < 31:
1160 return data[:1], 1, data[1:]
1165 raise DecodeError("unfinished tag")
1166 if indexbytes(data, i) & 0x80 == 0:
1169 return data[:i], i, data[i:]
1175 octets = bytearray(int_bytes_len(l) + 1)
1176 octets[0] = 0x80 | (len(octets) - 1)
1177 for i in six_xrange(len(octets) - 1, 0, -1):
1178 octets[i] = l & 0xFF
1180 return bytes(octets)
1183 def len_decode(data):
1186 :returns: (decoded length, length's length, remaining data)
1187 :raises LenIndefForm: if indefinite form encoding is met
1190 raise NotEnoughData("no data at all")
1191 first_octet = byte2int(data)
1192 if first_octet & 0x80 == 0:
1193 return first_octet, 1, data[1:]
1194 octets_num = first_octet & 0x7F
1195 if octets_num + 1 > len(data):
1196 raise NotEnoughData("encoded length is longer than data")
1198 raise LenIndefForm()
1199 if byte2int(data[1:]) == 0:
1200 raise DecodeError("leading zeros")
1202 for v in iterbytes(data[1:1 + octets_num]):
1205 raise DecodeError("long form instead of short one")
1206 return l, 1 + octets_num, data[1 + octets_num:]
1209 LEN1K = len_encode(1000)
1212 def write_full(writer, data):
1213 """Fully write provided data
1215 BytesIO does not guarantee that the whole data will be written at once.
1217 data = memoryview(data)
1219 while written != len(data):
1220 n = writer(data[written:])
1222 raise ValueError("can not write to buf")
1226 ########################################################################
1228 ########################################################################
1230 class AutoAddSlots(type):
1231 def __new__(cls, name, bases, _dict):
1232 _dict["__slots__"] = _dict.get("__slots__", ())
1233 return type.__new__(cls, name, bases, _dict)
1236 BasicState = namedtuple("BasicState", (
1249 ), **NAMEDTUPLE_KWARGS)
1252 @add_metaclass(AutoAddSlots)
1254 """Common ASN.1 object class
1256 All ASN.1 types are inherited from it. It has metaclass that
1257 automatically adds ``__slots__`` to all inherited classes.
1282 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1283 self._expl = getattr(self, "expl", None) if expl is None else expl
1284 if self.tag != self.tag_default and self._expl is not None:
1285 raise ValueError("implicit and explicit tags can not be set simultaneously")
1286 if self.tag is None:
1287 self._tag_order = None
1289 tag_class, _, tag_num = tag_decode(
1290 self.tag if self._expl is None else self._expl
1292 self._tag_order = (tag_class, tag_num)
1293 if default is not None:
1295 self.optional = optional
1296 self.offset, self.llen, self.vlen = _decoded
1298 self.expl_lenindef = False
1299 self.lenindef = False
1300 self.ber_encoded = False
1303 def ready(self): # pragma: no cover
1304 """Is object ready to be encoded?
1306 raise NotImplementedError()
1308 def _assert_ready(self):
1310 raise ObjNotReady(self.__class__.__name__)
1314 """Is either object or any elements inside is BER encoded?
1316 return self.expl_lenindef or self.lenindef or self.ber_encoded
1320 """Is object decoded?
1322 return (self.llen + self.vlen) > 0
1324 def __getstate__(self): # pragma: no cover
1325 """Used for making safe to be mutable pickleable copies
1327 raise NotImplementedError()
1329 def __setstate__(self, state):
1330 if state.version != __version__:
1331 raise ValueError("data is pickled by different PyDERASN version")
1332 self.tag = state.tag
1333 self._tag_order = state.tag_order
1334 self._expl = state.expl
1335 self.default = state.default
1336 self.optional = state.optional
1337 self.offset = state.offset
1338 self.llen = state.llen
1339 self.vlen = state.vlen
1340 self.expl_lenindef = state.expl_lenindef
1341 self.lenindef = state.lenindef
1342 self.ber_encoded = state.ber_encoded
1345 def tag_order(self):
1346 """Tag's (class, number) used for DER/CER sorting
1348 return self._tag_order
1351 def tag_order_cer(self):
1352 return self.tag_order
1356 """See :ref:`decoding`
1358 return len(self.tag)
1362 """See :ref:`decoding`
1364 return self.tlen + self.llen + self.vlen
1366 def __str__(self): # pragma: no cover
1367 return self.__bytes__() if PY2 else self.__unicode__()
1369 def __ne__(self, their):
1370 return not(self == their)
1372 def __gt__(self, their): # pragma: no cover
1373 return not(self < their)
1375 def __le__(self, their): # pragma: no cover
1376 return (self == their) or (self < their)
1378 def __ge__(self, their): # pragma: no cover
1379 return (self == their) or (self > their)
1381 def _encode(self): # pragma: no cover
1382 raise NotImplementedError()
1384 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode): # pragma: no cover
1385 yield NotImplemented
1388 """Encode the structure
1390 :returns: DER representation
1392 raw = self._encode()
1393 if self._expl is None:
1395 return b"".join((self._expl, len_encode(len(raw)), raw))
1397 def encode_cer(self, writer):
1398 if self._expl is not None:
1399 write_full(writer, self._expl + LENINDEF)
1400 if getattr(self, "der_forced", False):
1401 write_full(writer, self._encode())
1403 self._encode_cer(writer)
1404 if self._expl is not None:
1405 write_full(writer, EOC)
1407 def _encode_cer(self, writer):
1408 write_full(writer, self._encode())
1410 def hexencode(self):
1411 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1413 return hexenc(self.encode())
1423 _ctx_immutable=True,
1425 result = next(self.decode_evgen(
1437 _, obj, tail = result
1448 _ctx_immutable=True,
1453 :param data: either binary or memoryview
1454 :param int offset: initial data's offset
1455 :param bool leavemm: do we need to leave memoryview of remaining
1456 data as is, or convert it to bytes otherwise
1457 :param ctx: optional :ref:`context <ctx>` governing decoding process
1458 :param tag_only: decode only the tag, without length and contents
1459 (used only in Choice and Set structures, trying to
1460 determine if tag satisfies the schema)
1461 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1463 :returns: (Obj, remaining data)
1465 .. seealso:: :ref:`decoding`
1469 elif _ctx_immutable:
1471 tlv = memoryview(data)
1474 get_def_by_path(ctx.get("evgen_mode_upto", ()), decode_path) is not None
1477 if self._expl is None:
1478 for result in self._decode(
1481 decode_path=decode_path,
1484 evgen_mode=_evgen_mode,
1489 _decode_path, obj, tail = result
1490 if not _decode_path is decode_path:
1494 t, tlen, lv = tag_strip(tlv)
1495 except DecodeError as err:
1496 raise err.__class__(
1498 klass=self.__class__,
1499 decode_path=decode_path,
1504 klass=self.__class__,
1505 decode_path=decode_path,
1509 l, llen, v = len_decode(lv)
1510 except LenIndefForm as err:
1511 if not ctx.get("bered", False):
1512 raise err.__class__(
1514 klass=self.__class__,
1515 decode_path=decode_path,
1519 offset += tlen + llen
1520 for result in self._decode(
1523 decode_path=decode_path,
1526 evgen_mode=_evgen_mode,
1528 if tag_only: # pragma: no cover
1531 _decode_path, obj, tail = result
1532 if not _decode_path is decode_path:
1534 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1535 if eoc_expected.tobytes() != EOC:
1538 klass=self.__class__,
1539 decode_path=decode_path,
1543 obj.expl_lenindef = True
1544 except DecodeError as err:
1545 raise err.__class__(
1547 klass=self.__class__,
1548 decode_path=decode_path,
1553 raise NotEnoughData(
1554 "encoded length is longer than data",
1555 klass=self.__class__,
1556 decode_path=decode_path,
1559 for result in self._decode(
1561 offset=offset + tlen + llen,
1562 decode_path=decode_path,
1565 evgen_mode=_evgen_mode,
1567 if tag_only: # pragma: no cover
1570 _decode_path, obj, tail = result
1571 if not _decode_path is decode_path:
1573 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1575 "explicit tag out-of-bound, longer than data",
1576 klass=self.__class__,
1577 decode_path=decode_path,
1580 yield decode_path, obj, (tail if leavemm else tail.tobytes())
1582 def decod(self, data, offset=0, decode_path=(), ctx=None):
1583 """Decode the data, check that tail is empty
1585 :raises ExceedingData: if tail is not empty
1587 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1588 (decode without tail) that also checks that there is no
1591 obj, tail = self.decode(
1594 decode_path=decode_path,
1599 raise ExceedingData(len(tail))
1602 def hexdecode(self, data, *args, **kwargs):
1603 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1605 return self.decode(hexdec(data), *args, **kwargs)
1607 def hexdecod(self, data, *args, **kwargs):
1608 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1610 return self.decod(hexdec(data), *args, **kwargs)
1614 """See :ref:`decoding`
1616 return self._expl is not None
1620 """See :ref:`decoding`
1625 def expl_tlen(self):
1626 """See :ref:`decoding`
1628 return len(self._expl)
1631 def expl_llen(self):
1632 """See :ref:`decoding`
1634 if self.expl_lenindef:
1636 return len(len_encode(self.tlvlen))
1639 def expl_offset(self):
1640 """See :ref:`decoding`
1642 return self.offset - self.expl_tlen - self.expl_llen
1645 def expl_vlen(self):
1646 """See :ref:`decoding`
1651 def expl_tlvlen(self):
1652 """See :ref:`decoding`
1654 return self.expl_tlen + self.expl_llen + self.expl_vlen
1657 def fulloffset(self):
1658 """See :ref:`decoding`
1660 return self.expl_offset if self.expled else self.offset
1664 """See :ref:`decoding`
1666 return self.expl_tlvlen if self.expled else self.tlvlen
1668 def pps_lenindef(self, decode_path):
1669 if self.lenindef and not (
1670 getattr(self, "defined", None) is not None and
1671 self.defined[1].lenindef
1674 asn1_type_name="EOC",
1676 decode_path=decode_path,
1678 self.offset + self.tlvlen -
1679 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1687 if self.expl_lenindef:
1689 asn1_type_name="EOC",
1690 obj_name="EXPLICIT",
1691 decode_path=decode_path,
1692 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1701 def encode_cer(obj):
1702 """Encode to CER in memory
1705 obj.encode_cer(buf.write)
1706 return buf.getvalue()
1709 class DecodePathDefBy(object):
1710 """DEFINED BY representation inside decode path
1712 __slots__ = ("defined_by",)
1714 def __init__(self, defined_by):
1715 self.defined_by = defined_by
1717 def __ne__(self, their):
1718 return not(self == their)
1720 def __eq__(self, their):
1721 if not isinstance(their, self.__class__):
1723 return self.defined_by == their.defined_by
1726 return "DEFINED BY " + str(self.defined_by)
1729 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1732 ########################################################################
1734 ########################################################################
1736 PP = namedtuple("PP", (
1759 ), **NAMEDTUPLE_KWARGS)
1764 asn1_type_name="unknown",
1781 expl_lenindef=False,
1812 def _colourize(what, colour, with_colours, attrs=("bold",)):
1813 return colored(what, colour, attrs=attrs) if with_colours else what
1816 def colonize_hex(hexed):
1817 """Separate hexadecimal string with colons
1819 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1828 with_decode_path=False,
1829 decode_path_len_decrease=0,
1836 " " if pp.expl_offset is None else
1837 ("-%d" % (pp.offset - pp.expl_offset))
1839 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1841 col = _colourize(col, "red", with_colours, ())
1842 col += _colourize("B", "red", with_colours) if pp.bered else " "
1844 col = "[%d,%d,%4d]%s" % (
1848 LENINDEF_PP_CHAR if pp.lenindef else " "
1850 col = _colourize(col, "green", with_colours, ())
1852 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1853 if decode_path_len > 0:
1854 cols.append(" ." * decode_path_len)
1855 ent = pp.decode_path[-1]
1856 if isinstance(ent, DecodePathDefBy):
1857 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1858 value = str(ent.defined_by)
1861 len(oid_maps) > 0 and
1862 ent.defined_by.asn1_type_name ==
1863 ObjectIdentifier.asn1_type_name
1865 for oid_map in oid_maps:
1866 oid_name = oid_map.get(value)
1867 if oid_name is not None:
1868 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1870 if oid_name is None:
1871 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1873 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1874 if pp.expl is not None:
1875 klass, _, num = pp.expl
1876 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1877 cols.append(_colourize(col, "blue", with_colours))
1878 if pp.impl is not None:
1879 klass, _, num = pp.impl
1880 col = "[%s%d]" % (TagClassReprs[klass], num)
1881 cols.append(_colourize(col, "blue", with_colours))
1882 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1883 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1885 cols.append(_colourize("BER", "red", with_colours))
1886 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1887 if pp.value is not None:
1889 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1891 len(oid_maps) > 0 and
1892 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1894 for oid_map in oid_maps:
1895 oid_name = oid_map.get(value)
1896 if oid_name is not None:
1897 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1899 if pp.asn1_type_name == Integer.asn1_type_name:
1900 hex_repr = hex(int(pp.obj._value))[2:].upper()
1901 if len(hex_repr) % 2 != 0:
1902 hex_repr = "0" + hex_repr
1903 cols.append(_colourize(
1904 "(%s)" % colonize_hex(hex_repr),
1909 if pp.blob.__class__ == binary_type:
1910 cols.append(hexenc(pp.blob))
1911 elif pp.blob.__class__ == tuple:
1912 cols.append(", ".join(pp.blob))
1914 cols.append(_colourize("OPTIONAL", "red", with_colours))
1916 cols.append(_colourize("DEFAULT", "red", with_colours))
1917 if with_decode_path:
1918 cols.append(_colourize(
1919 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1923 return " ".join(cols)
1926 def pp_console_blob(pp, decode_path_len_decrease=0):
1927 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1928 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1929 if decode_path_len > 0:
1930 cols.append(" ." * (decode_path_len + 1))
1931 if pp.blob.__class__ == binary_type:
1932 blob = hexenc(pp.blob).upper()
1933 for i in six_xrange(0, len(blob), 32):
1934 chunk = blob[i:i + 32]
1935 yield " ".join(cols + [colonize_hex(chunk)])
1936 elif pp.blob.__class__ == tuple:
1937 yield " ".join(cols + [", ".join(pp.blob)])
1945 with_decode_path=False,
1946 decode_path_only=(),
1949 """Pretty print object
1951 :param Obj obj: object you want to pretty print
1952 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1953 Its human readable form is printed when OID is met
1954 :param big_blobs: if large binary objects are met (like OctetString
1955 values), do we need to print them too, on separate
1957 :param with_colours: colourize output, if ``termcolor`` library
1959 :param with_decode_path: print decode path
1960 :param decode_path_only: print only that specified decode path
1962 def _pprint_pps(pps):
1964 if hasattr(pp, "_fields"):
1966 decode_path_only != () and
1968 str(p) for p in pp.decode_path[:len(decode_path_only)]
1969 ) != decode_path_only
1973 yield pp_console_row(
1978 with_colours=with_colours,
1979 with_decode_path=with_decode_path,
1980 decode_path_len_decrease=len(decode_path_only),
1982 for row in pp_console_blob(
1984 decode_path_len_decrease=len(decode_path_only),
1988 yield pp_console_row(
1993 with_colours=with_colours,
1994 with_decode_path=with_decode_path,
1995 decode_path_len_decrease=len(decode_path_only),
1998 for row in _pprint_pps(pp):
2000 return "\n".join(_pprint_pps(obj.pps(decode_path)))
2003 ########################################################################
2004 # ASN.1 primitive types
2005 ########################################################################
2007 BooleanState = namedtuple(
2009 BasicState._fields + ("value",),
2015 """``BOOLEAN`` boolean type
2017 >>> b = Boolean(True)
2019 >>> b == Boolean(True)
2025 tag_default = tag_encode(1)
2026 asn1_type_name = "BOOLEAN"
2038 :param value: set the value. Either boolean type, or
2039 :py:class:`pyderasn.Boolean` object
2040 :param bytes impl: override default tag with ``IMPLICIT`` one
2041 :param bytes expl: override default tag with ``EXPLICIT`` one
2042 :param default: set default value. Type same as in ``value``
2043 :param bool optional: is object ``OPTIONAL`` in sequence
2045 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
2046 self._value = None if value is None else self._value_sanitize(value)
2047 if default is not None:
2048 default = self._value_sanitize(default)
2049 self.default = self.__class__(
2055 self._value = default
2057 def _value_sanitize(self, value):
2058 if value.__class__ == bool:
2060 if issubclass(value.__class__, Boolean):
2062 raise InvalidValueType((self.__class__, bool))
2066 return self._value is not None
2068 def __getstate__(self):
2069 return BooleanState(
2085 def __setstate__(self, state):
2086 super(Boolean, self).__setstate__(state)
2087 self._value = state.value
2089 def __nonzero__(self):
2090 self._assert_ready()
2094 self._assert_ready()
2097 def __eq__(self, their):
2098 if their.__class__ == bool:
2099 return self._value == their
2100 if not issubclass(their.__class__, Boolean):
2103 self._value == their._value and
2104 self.tag == their.tag and
2105 self._expl == their._expl
2116 return self.__class__(
2118 impl=self.tag if impl is None else impl,
2119 expl=self._expl if expl is None else expl,
2120 default=self.default if default is None else default,
2121 optional=self.optional if optional is None else optional,
2125 self._assert_ready()
2129 (b"\xFF" if self._value else b"\x00"),
2132 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2134 t, _, lv = tag_strip(tlv)
2135 except DecodeError as err:
2136 raise err.__class__(
2138 klass=self.__class__,
2139 decode_path=decode_path,
2144 klass=self.__class__,
2145 decode_path=decode_path,
2152 l, _, v = len_decode(lv)
2153 except DecodeError as err:
2154 raise err.__class__(
2156 klass=self.__class__,
2157 decode_path=decode_path,
2161 raise InvalidLength(
2162 "Boolean's length must be equal to 1",
2163 klass=self.__class__,
2164 decode_path=decode_path,
2168 raise NotEnoughData(
2169 "encoded length is longer than data",
2170 klass=self.__class__,
2171 decode_path=decode_path,
2174 first_octet = byte2int(v)
2176 if first_octet == 0:
2178 elif first_octet == 0xFF:
2180 elif ctx.get("bered", False):
2185 "unacceptable Boolean value",
2186 klass=self.__class__,
2187 decode_path=decode_path,
2190 obj = self.__class__(
2194 default=self.default,
2195 optional=self.optional,
2196 _decoded=(offset, 1, 1),
2198 obj.ber_encoded = ber_encoded
2199 yield decode_path, obj, v[1:]
2202 return pp_console_row(next(self.pps()))
2204 def pps(self, decode_path=()):
2207 asn1_type_name=self.asn1_type_name,
2208 obj_name=self.__class__.__name__,
2209 decode_path=decode_path,
2210 value=str(self._value) if self.ready else None,
2211 optional=self.optional,
2212 default=self == self.default,
2213 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2214 expl=None if self._expl is None else tag_decode(self._expl),
2219 expl_offset=self.expl_offset if self.expled else None,
2220 expl_tlen=self.expl_tlen if self.expled else None,
2221 expl_llen=self.expl_llen if self.expled else None,
2222 expl_vlen=self.expl_vlen if self.expled else None,
2223 expl_lenindef=self.expl_lenindef,
2224 ber_encoded=self.ber_encoded,
2227 for pp in self.pps_lenindef(decode_path):
2231 IntegerState = namedtuple(
2233 BasicState._fields + ("specs", "value", "bound_min", "bound_max"),
2239 """``INTEGER`` integer type
2241 >>> b = Integer(-123)
2243 >>> b == Integer(-123)
2248 >>> Integer(2, bounds=(1, 3))
2250 >>> Integer(5, bounds=(1, 3))
2251 Traceback (most recent call last):
2252 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2256 class Version(Integer):
2263 >>> v = Version("v1")
2270 {'v3': 2, 'v1': 0, 'v2': 1}
2272 __slots__ = ("specs", "_bound_min", "_bound_max")
2273 tag_default = tag_encode(2)
2274 asn1_type_name = "INTEGER"
2288 :param value: set the value. Either integer type, named value
2289 (if ``schema`` is specified in the class), or
2290 :py:class:`pyderasn.Integer` object
2291 :param bounds: set ``(MIN, MAX)`` value constraint.
2292 (-inf, +inf) by default
2293 :param bytes impl: override default tag with ``IMPLICIT`` one
2294 :param bytes expl: override default tag with ``EXPLICIT`` one
2295 :param default: set default value. Type same as in ``value``
2296 :param bool optional: is object ``OPTIONAL`` in sequence
2298 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2300 specs = getattr(self, "schema", {}) if _specs is None else _specs
2301 self.specs = specs if specs.__class__ == dict else dict(specs)
2302 self._bound_min, self._bound_max = getattr(
2305 (float("-inf"), float("+inf")),
2306 ) if bounds is None else bounds
2307 if value is not None:
2308 self._value = self._value_sanitize(value)
2309 if default is not None:
2310 default = self._value_sanitize(default)
2311 self.default = self.__class__(
2317 if self._value is None:
2318 self._value = default
2320 def _value_sanitize(self, value):
2321 if isinstance(value, integer_types):
2323 elif issubclass(value.__class__, Integer):
2324 value = value._value
2325 elif value.__class__ == str:
2326 value = self.specs.get(value)
2328 raise ObjUnknown("integer value: %s" % value)
2330 raise InvalidValueType((self.__class__, int, str))
2331 if not self._bound_min <= value <= self._bound_max:
2332 raise BoundsError(self._bound_min, value, self._bound_max)
2337 return self._value is not None
2339 def __getstate__(self):
2340 return IntegerState(
2359 def __setstate__(self, state):
2360 super(Integer, self).__setstate__(state)
2361 self.specs = state.specs
2362 self._value = state.value
2363 self._bound_min = state.bound_min
2364 self._bound_max = state.bound_max
2367 self._assert_ready()
2368 return int(self._value)
2371 self._assert_ready()
2374 bytes(self._expl or b"") +
2375 str(self._value).encode("ascii"),
2378 def __eq__(self, their):
2379 if isinstance(their, integer_types):
2380 return self._value == their
2381 if not issubclass(their.__class__, Integer):
2384 self._value == their._value and
2385 self.tag == their.tag and
2386 self._expl == their._expl
2389 def __lt__(self, their):
2390 return self._value < their._value
2394 """Return named representation (if exists) of the value
2396 for name, value in iteritems(self.specs):
2397 if value == self._value:
2410 return self.__class__(
2413 (self._bound_min, self._bound_max)
2414 if bounds is None else bounds
2416 impl=self.tag if impl is None else impl,
2417 expl=self._expl if expl is None else expl,
2418 default=self.default if default is None else default,
2419 optional=self.optional if optional is None else optional,
2424 self._assert_ready()
2428 octets = bytearray([0])
2432 octets = bytearray()
2434 octets.append((value & 0xFF) ^ 0xFF)
2436 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2439 octets = bytearray()
2441 octets.append(value & 0xFF)
2443 if octets[-1] & 0x80 > 0:
2446 octets = bytes(octets)
2448 bytes_len = ceil(value.bit_length() / 8) or 1
2451 octets = value.to_bytes(
2456 except OverflowError:
2460 return b"".join((self.tag, len_encode(len(octets)), octets))
2462 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2464 t, _, lv = tag_strip(tlv)
2465 except DecodeError as err:
2466 raise err.__class__(
2468 klass=self.__class__,
2469 decode_path=decode_path,
2474 klass=self.__class__,
2475 decode_path=decode_path,
2482 l, llen, v = len_decode(lv)
2483 except DecodeError as err:
2484 raise err.__class__(
2486 klass=self.__class__,
2487 decode_path=decode_path,
2491 raise NotEnoughData(
2492 "encoded length is longer than data",
2493 klass=self.__class__,
2494 decode_path=decode_path,
2498 raise NotEnoughData(
2500 klass=self.__class__,
2501 decode_path=decode_path,
2504 v, tail = v[:l], v[l:]
2505 first_octet = byte2int(v)
2507 second_octet = byte2int(v[1:])
2509 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2510 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2513 "non normalized integer",
2514 klass=self.__class__,
2515 decode_path=decode_path,
2520 if first_octet & 0x80 > 0:
2521 octets = bytearray()
2522 for octet in bytearray(v):
2523 octets.append(octet ^ 0xFF)
2524 for octet in octets:
2525 value = (value << 8) | octet
2529 for octet in bytearray(v):
2530 value = (value << 8) | octet
2532 value = int.from_bytes(v, byteorder="big", signed=True)
2534 obj = self.__class__(
2536 bounds=(self._bound_min, self._bound_max),
2539 default=self.default,
2540 optional=self.optional,
2542 _decoded=(offset, llen, l),
2544 except BoundsError as err:
2547 klass=self.__class__,
2548 decode_path=decode_path,
2551 yield decode_path, obj, tail
2554 return pp_console_row(next(self.pps()))
2556 def pps(self, decode_path=()):
2559 asn1_type_name=self.asn1_type_name,
2560 obj_name=self.__class__.__name__,
2561 decode_path=decode_path,
2562 value=(self.named or str(self._value)) if self.ready else None,
2563 optional=self.optional,
2564 default=self == self.default,
2565 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2566 expl=None if self._expl is None else tag_decode(self._expl),
2571 expl_offset=self.expl_offset if self.expled else None,
2572 expl_tlen=self.expl_tlen if self.expled else None,
2573 expl_llen=self.expl_llen if self.expled else None,
2574 expl_vlen=self.expl_vlen if self.expled else None,
2575 expl_lenindef=self.expl_lenindef,
2578 for pp in self.pps_lenindef(decode_path):
2582 BitStringState = namedtuple(
2584 BasicState._fields + ("specs", "value", "tag_constructed", "defined"),
2589 class BitString(Obj):
2590 """``BIT STRING`` bit string type
2592 >>> BitString(b"hello world")
2593 BIT STRING 88 bits 68656c6c6f20776f726c64
2596 >>> b == b"hello world"
2601 >>> BitString("'0A3B5F291CD'H")
2602 BIT STRING 44 bits 0a3b5f291cd0
2603 >>> b = BitString("'010110000000'B")
2604 BIT STRING 12 bits 5800
2607 >>> b[0], b[1], b[2], b[3]
2608 (False, True, False, True)
2612 [False, True, False, True, True, False, False, False, False, False, False, False]
2616 class KeyUsage(BitString):
2618 ("digitalSignature", 0),
2619 ("nonRepudiation", 1),
2620 ("keyEncipherment", 2),
2623 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2624 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2626 ['nonRepudiation', 'keyEncipherment']
2628 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2632 Pay attention that BIT STRING can be encoded both in primitive
2633 and constructed forms. Decoder always checks constructed form tag
2634 additionally to specified primitive one. If BER decoding is
2635 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2636 of DER restrictions.
2638 __slots__ = ("tag_constructed", "specs", "defined")
2639 tag_default = tag_encode(3)
2640 asn1_type_name = "BIT STRING"
2653 :param value: set the value. Either binary type, tuple of named
2654 values (if ``schema`` is specified in the class),
2655 string in ``'XXX...'B`` form, or
2656 :py:class:`pyderasn.BitString` object
2657 :param bytes impl: override default tag with ``IMPLICIT`` one
2658 :param bytes expl: override default tag with ``EXPLICIT`` one
2659 :param default: set default value. Type same as in ``value``
2660 :param bool optional: is object ``OPTIONAL`` in sequence
2662 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2663 specs = getattr(self, "schema", {}) if _specs is None else _specs
2664 self.specs = specs if specs.__class__ == dict else dict(specs)
2665 self._value = None if value is None else self._value_sanitize(value)
2666 if default is not None:
2667 default = self._value_sanitize(default)
2668 self.default = self.__class__(
2674 self._value = default
2676 tag_klass, _, tag_num = tag_decode(self.tag)
2677 self.tag_constructed = tag_encode(
2679 form=TagFormConstructed,
2683 def _bits2octets(self, bits):
2684 if len(self.specs) > 0:
2685 bits = bits.rstrip("0")
2687 bits += "0" * ((8 - (bit_len % 8)) % 8)
2688 octets = bytearray(len(bits) // 8)
2689 for i in six_xrange(len(octets)):
2690 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2691 return bit_len, bytes(octets)
2693 def _value_sanitize(self, value):
2694 if isinstance(value, (string_types, binary_type)):
2696 isinstance(value, string_types) and
2697 value.startswith("'")
2699 if value.endswith("'B"):
2701 if not frozenset(value) <= SET01:
2702 raise ValueError("B's coding contains unacceptable chars")
2703 return self._bits2octets(value)
2704 if value.endswith("'H"):
2708 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2710 if value.__class__ == binary_type:
2711 return (len(value) * 8, value)
2712 raise InvalidValueType((self.__class__, string_types, binary_type))
2713 if value.__class__ == tuple:
2716 isinstance(value[0], integer_types) and
2717 value[1].__class__ == binary_type
2722 bit = self.specs.get(name)
2724 raise ObjUnknown("BitString value: %s" % name)
2727 return self._bits2octets("")
2728 bits = frozenset(bits)
2729 return self._bits2octets("".join(
2730 ("1" if bit in bits else "0")
2731 for bit in six_xrange(max(bits) + 1)
2733 if issubclass(value.__class__, BitString):
2735 raise InvalidValueType((self.__class__, binary_type, string_types))
2739 return self._value is not None
2741 def __getstate__(self):
2742 return BitStringState(
2757 self.tag_constructed,
2761 def __setstate__(self, state):
2762 super(BitString, self).__setstate__(state)
2763 self.specs = state.specs
2764 self._value = state.value
2765 self.tag_constructed = state.tag_constructed
2766 self.defined = state.defined
2769 self._assert_ready()
2770 for i in six_xrange(self._value[0]):
2775 """Returns number of bits in the string
2777 self._assert_ready()
2778 return self._value[0]
2780 def __bytes__(self):
2781 self._assert_ready()
2782 return self._value[1]
2784 def __eq__(self, their):
2785 if their.__class__ == bytes:
2786 return self._value[1] == their
2787 if not issubclass(their.__class__, BitString):
2790 self._value == their._value and
2791 self.tag == their.tag and
2792 self._expl == their._expl
2797 """Named representation (if exists) of the bits
2799 :returns: [str(name), ...]
2801 return [name for name, bit in iteritems(self.specs) if self[bit]]
2811 return self.__class__(
2813 impl=self.tag if impl is None else impl,
2814 expl=self._expl if expl is None else expl,
2815 default=self.default if default is None else default,
2816 optional=self.optional if optional is None else optional,
2820 def __getitem__(self, key):
2821 if key.__class__ == int:
2822 bit_len, octets = self._value
2826 byte2int(memoryview(octets)[key // 8:]) >>
2829 if isinstance(key, string_types):
2830 value = self.specs.get(key)
2832 raise ObjUnknown("BitString value: %s" % key)
2834 raise InvalidValueType((int, str))
2837 self._assert_ready()
2838 bit_len, octets = self._value
2841 len_encode(len(octets) + 1),
2842 int2byte((8 - bit_len % 8) % 8),
2846 def _encode_cer(self, writer):
2847 bit_len, octets = self._value
2848 if len(octets) + 1 <= 1000:
2849 write_full(writer, self._encode())
2851 write_full(writer, self.tag_constructed)
2852 write_full(writer, LENINDEF)
2853 for offset in six_xrange(0, (len(octets) // 999) * 999, 999):
2854 write_full(writer, b"".join((
2855 BitString.tag_default,
2858 octets[offset:offset + 999],
2860 tail = octets[offset+999:]
2862 tail = int2byte((8 - bit_len % 8) % 8) + tail
2863 write_full(writer, b"".join((
2864 BitString.tag_default,
2865 len_encode(len(tail)),
2868 write_full(writer, EOC)
2870 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
2872 t, tlen, lv = tag_strip(tlv)
2873 except DecodeError as err:
2874 raise err.__class__(
2876 klass=self.__class__,
2877 decode_path=decode_path,
2881 if tag_only: # pragma: no cover
2885 l, llen, v = len_decode(lv)
2886 except DecodeError as err:
2887 raise err.__class__(
2889 klass=self.__class__,
2890 decode_path=decode_path,
2894 raise NotEnoughData(
2895 "encoded length is longer than data",
2896 klass=self.__class__,
2897 decode_path=decode_path,
2901 raise NotEnoughData(
2903 klass=self.__class__,
2904 decode_path=decode_path,
2907 pad_size = byte2int(v)
2908 if l == 1 and pad_size != 0:
2910 "invalid empty value",
2911 klass=self.__class__,
2912 decode_path=decode_path,
2918 klass=self.__class__,
2919 decode_path=decode_path,
2922 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2925 klass=self.__class__,
2926 decode_path=decode_path,
2929 v, tail = v[:l], v[l:]
2930 bit_len = (len(v) - 1) * 8 - pad_size
2931 obj = self.__class__(
2932 value=None if evgen_mode else (bit_len, v[1:].tobytes()),
2935 default=self.default,
2936 optional=self.optional,
2938 _decoded=(offset, llen, l),
2941 obj._value = (bit_len, None)
2942 yield decode_path, obj, tail
2944 if t != self.tag_constructed:
2946 klass=self.__class__,
2947 decode_path=decode_path,
2950 if not ctx.get("bered", False):
2952 "unallowed BER constructed encoding",
2953 klass=self.__class__,
2954 decode_path=decode_path,
2957 if tag_only: # pragma: no cover
2962 l, llen, v = len_decode(lv)
2963 except LenIndefForm:
2964 llen, l, v = 1, 0, lv[1:]
2966 except DecodeError as err:
2967 raise err.__class__(
2969 klass=self.__class__,
2970 decode_path=decode_path,
2974 raise NotEnoughData(
2975 "encoded length is longer than data",
2976 klass=self.__class__,
2977 decode_path=decode_path,
2980 if not lenindef and l == 0:
2981 raise NotEnoughData(
2983 klass=self.__class__,
2984 decode_path=decode_path,
2988 sub_offset = offset + tlen + llen
2992 if v[:EOC_LEN].tobytes() == EOC:
2999 "chunk out of bounds",
3000 klass=self.__class__,
3001 decode_path=decode_path + (str(len(chunks) - 1),),
3002 offset=chunks[-1].offset,
3004 sub_decode_path = decode_path + (str(len(chunks)),)
3007 for _decode_path, chunk, v_tail in BitString().decode_evgen(
3010 decode_path=sub_decode_path,
3013 _ctx_immutable=False,
3015 yield _decode_path, chunk, v_tail
3017 _, chunk, v_tail = next(BitString().decode_evgen(
3020 decode_path=sub_decode_path,
3023 _ctx_immutable=False,
3028 "expected BitString encoded chunk",
3029 klass=self.__class__,
3030 decode_path=sub_decode_path,
3033 chunks.append(chunk)
3034 sub_offset += chunk.tlvlen
3035 vlen += chunk.tlvlen
3037 if len(chunks) == 0:
3040 klass=self.__class__,
3041 decode_path=decode_path,
3046 for chunk_i, chunk in enumerate(chunks[:-1]):
3047 if chunk.bit_len % 8 != 0:
3049 "BitString chunk is not multiple of 8 bits",
3050 klass=self.__class__,
3051 decode_path=decode_path + (str(chunk_i),),
3052 offset=chunk.offset,
3055 values.append(bytes(chunk))
3056 bit_len += chunk.bit_len
3057 chunk_last = chunks[-1]
3059 values.append(bytes(chunk_last))
3060 bit_len += chunk_last.bit_len
3061 obj = self.__class__(
3062 value=None if evgen_mode else (bit_len, b"".join(values)),
3065 default=self.default,
3066 optional=self.optional,
3068 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3071 obj._value = (bit_len, None)
3072 obj.lenindef = lenindef
3073 obj.ber_encoded = True
3074 yield decode_path, obj, (v[EOC_LEN:] if lenindef else v)
3077 return pp_console_row(next(self.pps()))
3079 def pps(self, decode_path=()):
3083 bit_len, blob = self._value
3084 value = "%d bits" % bit_len
3085 if len(self.specs) > 0 and blob is not None:
3086 blob = tuple(self.named)
3089 asn1_type_name=self.asn1_type_name,
3090 obj_name=self.__class__.__name__,
3091 decode_path=decode_path,
3094 optional=self.optional,
3095 default=self == self.default,
3096 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3097 expl=None if self._expl is None else tag_decode(self._expl),
3102 expl_offset=self.expl_offset if self.expled else None,
3103 expl_tlen=self.expl_tlen if self.expled else None,
3104 expl_llen=self.expl_llen if self.expled else None,
3105 expl_vlen=self.expl_vlen if self.expled else None,
3106 expl_lenindef=self.expl_lenindef,
3107 lenindef=self.lenindef,
3108 ber_encoded=self.ber_encoded,
3111 defined_by, defined = self.defined or (None, None)
3112 if defined_by is not None:
3114 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3116 for pp in self.pps_lenindef(decode_path):
3120 OctetStringState = namedtuple(
3122 BasicState._fields + (
3133 class OctetString(Obj):
3134 """``OCTET STRING`` binary string type
3136 >>> s = OctetString(b"hello world")
3137 OCTET STRING 11 bytes 68656c6c6f20776f726c64
3138 >>> s == OctetString(b"hello world")
3143 >>> OctetString(b"hello", bounds=(4, 4))
3144 Traceback (most recent call last):
3145 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
3146 >>> OctetString(b"hell", bounds=(4, 4))
3147 OCTET STRING 4 bytes 68656c6c
3149 Memoryviews can be used as a values. If memoryview is made on
3150 mmap-ed file, then it does not take storage inside OctetString
3151 itself. In CER encoding mode it will be streamed to the specified
3152 writer, copying 1 KB chunks.
3154 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
3155 tag_default = tag_encode(4)
3156 asn1_type_name = "OCTET STRING"
3157 evgen_mode_skip_value = True
3171 :param value: set the value. Either binary type, or
3172 :py:class:`pyderasn.OctetString` object
3173 :param bounds: set ``(MIN, MAX)`` value size constraint.
3174 (-inf, +inf) by default
3175 :param bytes impl: override default tag with ``IMPLICIT`` one
3176 :param bytes expl: override default tag with ``EXPLICIT`` one
3177 :param default: set default value. Type same as in ``value``
3178 :param bool optional: is object ``OPTIONAL`` in sequence
3180 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
3182 self._bound_min, self._bound_max = getattr(
3186 ) if bounds is None else bounds
3187 if value is not None:
3188 self._value = self._value_sanitize(value)
3189 if default is not None:
3190 default = self._value_sanitize(default)
3191 self.default = self.__class__(
3196 if self._value is None:
3197 self._value = default
3199 tag_klass, _, tag_num = tag_decode(self.tag)
3200 self.tag_constructed = tag_encode(
3202 form=TagFormConstructed,
3206 def _value_sanitize(self, value):
3207 if value.__class__ == binary_type or value.__class__ == memoryview:
3209 elif issubclass(value.__class__, OctetString):
3210 value = value._value
3212 raise InvalidValueType((self.__class__, bytes, memoryview))
3213 if not self._bound_min <= len(value) <= self._bound_max:
3214 raise BoundsError(self._bound_min, len(value), self._bound_max)
3219 return self._value is not None
3221 def __getstate__(self):
3222 return OctetStringState(
3238 self.tag_constructed,
3242 def __setstate__(self, state):
3243 super(OctetString, self).__setstate__(state)
3244 self._value = state.value
3245 self._bound_min = state.bound_min
3246 self._bound_max = state.bound_max
3247 self.tag_constructed = state.tag_constructed
3248 self.defined = state.defined
3250 def __bytes__(self):
3251 self._assert_ready()
3252 return bytes(self._value)
3254 def __eq__(self, their):
3255 if their.__class__ == binary_type:
3256 return self._value == their
3257 if not issubclass(their.__class__, OctetString):
3260 self._value == their._value and
3261 self.tag == their.tag and
3262 self._expl == their._expl
3265 def __lt__(self, their):
3266 return self._value < their._value
3277 return self.__class__(
3280 (self._bound_min, self._bound_max)
3281 if bounds is None else bounds
3283 impl=self.tag if impl is None else impl,
3284 expl=self._expl if expl is None else expl,
3285 default=self.default if default is None else default,
3286 optional=self.optional if optional is None else optional,
3290 self._assert_ready()
3293 len_encode(len(self._value)),
3297 def _encode_cer(self, writer):
3298 octets = self._value
3299 if len(octets) <= 1000:
3300 write_full(writer, self._encode())
3302 write_full(writer, self.tag_constructed)
3303 write_full(writer, LENINDEF)
3304 for offset in six_xrange(0, (len(octets) // 1000) * 1000, 1000):
3305 write_full(writer, b"".join((
3306 OctetString.tag_default,
3308 octets[offset:offset + 1000],
3310 tail = octets[offset+1000:]
3312 write_full(writer, b"".join((
3313 OctetString.tag_default,
3314 len_encode(len(tail)),
3317 write_full(writer, EOC)
3319 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3321 t, tlen, lv = tag_strip(tlv)
3322 except DecodeError as err:
3323 raise err.__class__(
3325 klass=self.__class__,
3326 decode_path=decode_path,
3334 l, llen, v = len_decode(lv)
3335 except DecodeError as err:
3336 raise err.__class__(
3338 klass=self.__class__,
3339 decode_path=decode_path,
3343 raise NotEnoughData(
3344 "encoded length is longer than data",
3345 klass=self.__class__,
3346 decode_path=decode_path,
3349 v, tail = v[:l], v[l:]
3350 if evgen_mode and not self._bound_min <= len(v) <= self._bound_max:
3352 msg=str(BoundsError(self._bound_min, len(v), self._bound_max)),
3353 klass=self.__class__,
3354 decode_path=decode_path,
3358 obj = self.__class__(
3360 None if (evgen_mode and self.evgen_mode_skip_value)
3363 bounds=(self._bound_min, self._bound_max),
3366 default=self.default,
3367 optional=self.optional,
3368 _decoded=(offset, llen, l),
3371 except DecodeError as err:
3374 klass=self.__class__,
3375 decode_path=decode_path,
3378 except BoundsError as err:
3381 klass=self.__class__,
3382 decode_path=decode_path,
3385 yield decode_path, obj, tail
3387 if t != self.tag_constructed:
3389 klass=self.__class__,
3390 decode_path=decode_path,
3393 if not ctx.get("bered", False):
3395 "unallowed BER constructed encoding",
3396 klass=self.__class__,
3397 decode_path=decode_path,
3405 l, llen, v = len_decode(lv)
3406 except LenIndefForm:
3407 llen, l, v = 1, 0, lv[1:]
3409 except DecodeError as err:
3410 raise err.__class__(
3412 klass=self.__class__,
3413 decode_path=decode_path,
3417 raise NotEnoughData(
3418 "encoded length is longer than data",
3419 klass=self.__class__,
3420 decode_path=decode_path,
3425 sub_offset = offset + tlen + llen
3430 if v[:EOC_LEN].tobytes() == EOC:
3437 "chunk out of bounds",
3438 klass=self.__class__,
3439 decode_path=decode_path + (str(len(chunks) - 1),),
3440 offset=chunks[-1].offset,
3444 sub_decode_path = decode_path + (str(chunks_count),)
3445 for _decode_path, chunk, v_tail in OctetString().decode_evgen(
3448 decode_path=sub_decode_path,
3451 _ctx_immutable=False,
3453 yield _decode_path, chunk, v_tail
3454 if not chunk.ber_encoded:
3455 payload_len += chunk.vlen
3458 sub_decode_path = decode_path + (str(len(chunks)),)
3459 _, chunk, v_tail = next(OctetString().decode_evgen(
3462 decode_path=sub_decode_path,
3465 _ctx_immutable=False,
3468 chunks.append(chunk)
3471 "expected OctetString encoded chunk",
3472 klass=self.__class__,
3473 decode_path=sub_decode_path,
3476 sub_offset += chunk.tlvlen
3477 vlen += chunk.tlvlen
3479 if evgen_mode and not self._bound_min <= payload_len <= self._bound_max:
3481 msg=str(BoundsError(self._bound_min, payload_len, self._bound_max)),
3482 klass=self.__class__,
3483 decode_path=decode_path,
3487 obj = self.__class__(
3489 None if evgen_mode else
3490 b"".join(bytes(chunk) for chunk in chunks)
3492 bounds=(self._bound_min, self._bound_max),
3495 default=self.default,
3496 optional=self.optional,
3497 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3500 except DecodeError as err:
3503 klass=self.__class__,
3504 decode_path=decode_path,
3507 except BoundsError as err:
3510 klass=self.__class__,
3511 decode_path=decode_path,
3514 obj.lenindef = lenindef
3515 obj.ber_encoded = True
3516 yield decode_path, obj, (v[EOC_LEN:] if lenindef else v)
3519 return pp_console_row(next(self.pps()))
3521 def pps(self, decode_path=()):
3524 asn1_type_name=self.asn1_type_name,
3525 obj_name=self.__class__.__name__,
3526 decode_path=decode_path,
3527 value=("%d bytes" % len(self._value)) if self.ready else None,
3528 blob=self._value if self.ready else None,
3529 optional=self.optional,
3530 default=self == self.default,
3531 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3532 expl=None if self._expl is None else tag_decode(self._expl),
3537 expl_offset=self.expl_offset if self.expled else None,
3538 expl_tlen=self.expl_tlen if self.expled else None,
3539 expl_llen=self.expl_llen if self.expled else None,
3540 expl_vlen=self.expl_vlen if self.expled else None,
3541 expl_lenindef=self.expl_lenindef,
3542 lenindef=self.lenindef,
3543 ber_encoded=self.ber_encoded,
3546 defined_by, defined = self.defined or (None, None)
3547 if defined_by is not None:
3549 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3551 for pp in self.pps_lenindef(decode_path):
3555 def agg_octet_string(evgens, decode_path, raw, writer):
3556 """Aggregate constructed string (OctetString and its derivatives)
3558 :param evgens: iterator of generated events
3559 :param decode_path: points to the string we want to decode
3560 :param raw: slicebable (memoryview, bytearray, etc) with
3561 the data evgens are generated one
3562 :param writer: buffer.write where string is going to be saved
3564 decode_path_len = len(decode_path)
3565 for dp, obj, _ in evgens:
3566 if dp[:decode_path_len] != decode_path:
3568 if not obj.ber_encoded:
3569 write_full(writer, raw[
3570 obj.offset + obj.tlen + obj.llen:
3571 obj.offset + obj.tlen + obj.llen + obj.vlen -
3572 (EOC_LEN if obj.expl_lenindef else 0)
3574 if len(dp) == decode_path_len:
3578 NullState = namedtuple("NullState", BasicState._fields, **NAMEDTUPLE_KWARGS)
3582 """``NULL`` null object
3590 tag_default = tag_encode(5)
3591 asn1_type_name = "NULL"
3595 value=None, # unused, but Sequence passes it
3602 :param bytes impl: override default tag with ``IMPLICIT`` one
3603 :param bytes expl: override default tag with ``EXPLICIT`` one
3604 :param bool optional: is object ``OPTIONAL`` in sequence
3606 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3613 def __getstate__(self):
3629 def __eq__(self, their):
3630 if not issubclass(their.__class__, Null):
3633 self.tag == their.tag and
3634 self._expl == their._expl
3644 return self.__class__(
3645 impl=self.tag if impl is None else impl,
3646 expl=self._expl if expl is None else expl,
3647 optional=self.optional if optional is None else optional,
3651 return self.tag + len_encode(0)
3653 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3655 t, _, lv = tag_strip(tlv)
3656 except DecodeError as err:
3657 raise err.__class__(
3659 klass=self.__class__,
3660 decode_path=decode_path,
3665 klass=self.__class__,
3666 decode_path=decode_path,
3669 if tag_only: # pragma: no cover
3673 l, _, v = len_decode(lv)
3674 except DecodeError as err:
3675 raise err.__class__(
3677 klass=self.__class__,
3678 decode_path=decode_path,
3682 raise InvalidLength(
3683 "Null must have zero length",
3684 klass=self.__class__,
3685 decode_path=decode_path,
3688 obj = self.__class__(
3691 optional=self.optional,
3692 _decoded=(offset, 1, 0),
3694 yield decode_path, obj, v
3697 return pp_console_row(next(self.pps()))
3699 def pps(self, decode_path=()):
3702 asn1_type_name=self.asn1_type_name,
3703 obj_name=self.__class__.__name__,
3704 decode_path=decode_path,
3705 optional=self.optional,
3706 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3707 expl=None if self._expl is None else tag_decode(self._expl),
3712 expl_offset=self.expl_offset if self.expled else None,
3713 expl_tlen=self.expl_tlen if self.expled else None,
3714 expl_llen=self.expl_llen if self.expled else None,
3715 expl_vlen=self.expl_vlen if self.expled else None,
3716 expl_lenindef=self.expl_lenindef,
3719 for pp in self.pps_lenindef(decode_path):
3723 ObjectIdentifierState = namedtuple(
3724 "ObjectIdentifierState",
3725 BasicState._fields + ("value", "defines"),
3730 class ObjectIdentifier(Obj):
3731 """``OBJECT IDENTIFIER`` OID type
3733 >>> oid = ObjectIdentifier((1, 2, 3))
3734 OBJECT IDENTIFIER 1.2.3
3735 >>> oid == ObjectIdentifier("1.2.3")
3741 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3742 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3744 >>> str(ObjectIdentifier((3, 1)))
3745 Traceback (most recent call last):
3746 pyderasn.InvalidOID: unacceptable first arc value
3748 __slots__ = ("defines",)
3749 tag_default = tag_encode(6)
3750 asn1_type_name = "OBJECT IDENTIFIER"
3763 :param value: set the value. Either tuples of integers,
3764 string of "."-concatenated integers, or
3765 :py:class:`pyderasn.ObjectIdentifier` object
3766 :param defines: sequence of tuples. Each tuple has two elements.
3767 First one is relative to current one decode
3768 path, aiming to the field defined by that OID.
3769 Read about relative path in
3770 :py:func:`pyderasn.abs_decode_path`. Second
3771 tuple element is ``{OID: pyderasn.Obj()}``
3772 dictionary, mapping between current OID value
3773 and structure applied to defined field.
3774 :ref:`Read about DEFINED BY <definedby>`
3775 :param bytes impl: override default tag with ``IMPLICIT`` one
3776 :param bytes expl: override default tag with ``EXPLICIT`` one
3777 :param default: set default value. Type same as in ``value``
3778 :param bool optional: is object ``OPTIONAL`` in sequence
3780 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3782 if value is not None:
3783 self._value = self._value_sanitize(value)
3784 if default is not None:
3785 default = self._value_sanitize(default)
3786 self.default = self.__class__(
3791 if self._value is None:
3792 self._value = default
3793 self.defines = defines
3795 def __add__(self, their):
3796 if their.__class__ == tuple:
3797 return self.__class__(self._value + their)
3798 if isinstance(their, self.__class__):
3799 return self.__class__(self._value + their._value)
3800 raise InvalidValueType((self.__class__, tuple))
3802 def _value_sanitize(self, value):
3803 if issubclass(value.__class__, ObjectIdentifier):
3805 if isinstance(value, string_types):
3807 value = tuple(pureint(arc) for arc in value.split("."))
3809 raise InvalidOID("unacceptable arcs values")
3810 if value.__class__ == tuple:
3812 raise InvalidOID("less than 2 arcs")
3813 first_arc = value[0]
3814 if first_arc in (0, 1):
3815 if not (0 <= value[1] <= 39):
3816 raise InvalidOID("second arc is too wide")
3817 elif first_arc == 2:
3820 raise InvalidOID("unacceptable first arc value")
3821 if not all(arc >= 0 for arc in value):
3822 raise InvalidOID("negative arc value")
3824 raise InvalidValueType((self.__class__, str, tuple))
3828 return self._value is not None
3830 def __getstate__(self):
3831 return ObjectIdentifierState(
3848 def __setstate__(self, state):
3849 super(ObjectIdentifier, self).__setstate__(state)
3850 self._value = state.value
3851 self.defines = state.defines
3854 self._assert_ready()
3855 return iter(self._value)
3858 return ".".join(str(arc) for arc in self._value or ())
3861 self._assert_ready()
3864 bytes(self._expl or b"") +
3865 str(self._value).encode("ascii"),
3868 def __eq__(self, their):
3869 if their.__class__ == tuple:
3870 return self._value == their
3871 if not issubclass(their.__class__, ObjectIdentifier):
3874 self.tag == their.tag and
3875 self._expl == their._expl and
3876 self._value == their._value
3879 def __lt__(self, their):
3880 return self._value < their._value
3891 return self.__class__(
3893 defines=self.defines if defines is None else defines,
3894 impl=self.tag if impl is None else impl,
3895 expl=self._expl if expl is None else expl,
3896 default=self.default if default is None else default,
3897 optional=self.optional if optional is None else optional,
3901 self._assert_ready()
3903 first_value = value[1]
3904 first_arc = value[0]
3907 elif first_arc == 1:
3909 elif first_arc == 2:
3911 else: # pragma: no cover
3912 raise RuntimeError("invalid arc is stored")
3913 octets = [zero_ended_encode(first_value)]
3914 for arc in value[2:]:
3915 octets.append(zero_ended_encode(arc))
3916 v = b"".join(octets)
3917 return b"".join((self.tag, len_encode(len(v)), v))
3919 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
3921 t, _, lv = tag_strip(tlv)
3922 except DecodeError as err:
3923 raise err.__class__(
3925 klass=self.__class__,
3926 decode_path=decode_path,
3931 klass=self.__class__,
3932 decode_path=decode_path,
3935 if tag_only: # pragma: no cover
3939 l, llen, v = len_decode(lv)
3940 except DecodeError as err:
3941 raise err.__class__(
3943 klass=self.__class__,
3944 decode_path=decode_path,
3948 raise NotEnoughData(
3949 "encoded length is longer than data",
3950 klass=self.__class__,
3951 decode_path=decode_path,
3955 raise NotEnoughData(
3957 klass=self.__class__,
3958 decode_path=decode_path,
3961 v, tail = v[:l], v[l:]
3968 octet = indexbytes(v, i)
3969 if i == 0 and octet == 0x80:
3970 if ctx.get("bered", False):
3973 raise DecodeError("non normalized arc encoding")
3974 arc = (arc << 7) | (octet & 0x7F)
3975 if octet & 0x80 == 0:
3983 klass=self.__class__,
3984 decode_path=decode_path,
3988 second_arc = arcs[0]
3989 if 0 <= second_arc <= 39:
3991 elif 40 <= second_arc <= 79:
3997 obj = self.__class__(
3998 value=tuple([first_arc, second_arc] + arcs[1:]),
4001 default=self.default,
4002 optional=self.optional,
4003 _decoded=(offset, llen, l),
4006 obj.ber_encoded = True
4007 yield decode_path, obj, tail
4010 return pp_console_row(next(self.pps()))
4012 def pps(self, decode_path=()):
4015 asn1_type_name=self.asn1_type_name,
4016 obj_name=self.__class__.__name__,
4017 decode_path=decode_path,
4018 value=str(self) if self.ready else None,
4019 optional=self.optional,
4020 default=self == self.default,
4021 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4022 expl=None if self._expl is None else tag_decode(self._expl),
4027 expl_offset=self.expl_offset if self.expled else None,
4028 expl_tlen=self.expl_tlen if self.expled else None,
4029 expl_llen=self.expl_llen if self.expled else None,
4030 expl_vlen=self.expl_vlen if self.expled else None,
4031 expl_lenindef=self.expl_lenindef,
4032 ber_encoded=self.ber_encoded,
4035 for pp in self.pps_lenindef(decode_path):
4039 class Enumerated(Integer):
4040 """``ENUMERATED`` integer type
4042 This type is identical to :py:class:`pyderasn.Integer`, but requires
4043 schema to be specified and does not accept values missing from it.
4046 tag_default = tag_encode(10)
4047 asn1_type_name = "ENUMERATED"
4058 bounds=None, # dummy argument, workability for Integer.decode
4060 super(Enumerated, self).__init__(
4061 value, bounds, impl, expl, default, optional, _specs, _decoded,
4063 if len(self.specs) == 0:
4064 raise ValueError("schema must be specified")
4066 def _value_sanitize(self, value):
4067 if isinstance(value, self.__class__):
4068 value = value._value
4069 elif isinstance(value, integer_types):
4070 for _value in itervalues(self.specs):
4075 "unknown integer value: %s" % value,
4076 klass=self.__class__,
4078 elif isinstance(value, string_types):
4079 value = self.specs.get(value)
4081 raise ObjUnknown("integer value: %s" % value)
4083 raise InvalidValueType((self.__class__, int, str))
4095 return self.__class__(
4097 impl=self.tag if impl is None else impl,
4098 expl=self._expl if expl is None else expl,
4099 default=self.default if default is None else default,
4100 optional=self.optional if optional is None else optional,
4105 def escape_control_unicode(c):
4106 if unicat(c)[0] == "C":
4107 c = repr(c).lstrip("u").strip("'")
4111 class CommonString(OctetString):
4112 """Common class for all strings
4114 Everything resembles :py:class:`pyderasn.OctetString`, except
4115 ability to deal with unicode text strings.
4117 >>> hexenc("привет мир".encode("utf-8"))
4118 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
4119 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
4121 >>> s = UTF8String("привет мир")
4122 UTF8String UTF8String привет мир
4124 'привет мир'
4125 >>> hexenc(bytes(s))
4126 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
4128 >>> PrintableString("привет мир")
4129 Traceback (most recent call last):
4130 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
4132 >>> BMPString("ада", bounds=(2, 2))
4133 Traceback (most recent call last):
4134 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
4135 >>> s = BMPString("ад", bounds=(2, 2))
4138 >>> hexenc(bytes(s))
4146 * - :py:class:`pyderasn.UTF8String`
4148 * - :py:class:`pyderasn.NumericString`
4150 * - :py:class:`pyderasn.PrintableString`
4152 * - :py:class:`pyderasn.TeletexString`
4154 * - :py:class:`pyderasn.T61String`
4156 * - :py:class:`pyderasn.VideotexString`
4158 * - :py:class:`pyderasn.IA5String`
4160 * - :py:class:`pyderasn.GraphicString`
4162 * - :py:class:`pyderasn.VisibleString`
4164 * - :py:class:`pyderasn.ISO646String`
4166 * - :py:class:`pyderasn.GeneralString`
4168 * - :py:class:`pyderasn.UniversalString`
4170 * - :py:class:`pyderasn.BMPString`
4175 def _value_sanitize(self, value):
4177 value_decoded = None
4178 if isinstance(value, self.__class__):
4179 value_raw = value._value
4180 elif value.__class__ == text_type:
4181 value_decoded = value
4182 elif value.__class__ == binary_type:
4185 raise InvalidValueType((self.__class__, text_type, binary_type))
4188 value_decoded.encode(self.encoding)
4189 if value_raw is None else value_raw
4192 value_raw.decode(self.encoding)
4193 if value_decoded is None else value_decoded
4195 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4196 raise DecodeError(str(err))
4197 if not self._bound_min <= len(value_decoded) <= self._bound_max:
4205 def __eq__(self, their):
4206 if their.__class__ == binary_type:
4207 return self._value == their
4208 if their.__class__ == text_type:
4209 return self._value == their.encode(self.encoding)
4210 if not isinstance(their, self.__class__):
4213 self._value == their._value and
4214 self.tag == their.tag and
4215 self._expl == their._expl
4218 def __unicode__(self):
4220 return self._value.decode(self.encoding)
4221 return text_type(self._value)
4224 return pp_console_row(next(self.pps(no_unicode=PY2)))
4226 def pps(self, decode_path=(), no_unicode=False):
4230 hexenc(bytes(self)) if no_unicode else
4231 "".join(escape_control_unicode(c) for c in self.__unicode__())
4235 asn1_type_name=self.asn1_type_name,
4236 obj_name=self.__class__.__name__,
4237 decode_path=decode_path,
4239 optional=self.optional,
4240 default=self == self.default,
4241 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4242 expl=None if self._expl is None else tag_decode(self._expl),
4247 expl_offset=self.expl_offset if self.expled else None,
4248 expl_tlen=self.expl_tlen if self.expled else None,
4249 expl_llen=self.expl_llen if self.expled else None,
4250 expl_vlen=self.expl_vlen if self.expled else None,
4251 expl_lenindef=self.expl_lenindef,
4252 ber_encoded=self.ber_encoded,
4255 for pp in self.pps_lenindef(decode_path):
4259 class UTF8String(CommonString):
4261 tag_default = tag_encode(12)
4263 asn1_type_name = "UTF8String"
4266 class AllowableCharsMixin(object):
4268 def allowable_chars(self):
4270 return self._allowable_chars
4271 return frozenset(six_unichr(c) for c in self._allowable_chars)
4274 class NumericString(AllowableCharsMixin, CommonString):
4277 Its value is properly sanitized: only ASCII digits with spaces can
4280 >>> NumericString().allowable_chars
4281 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
4284 tag_default = tag_encode(18)
4286 asn1_type_name = "NumericString"
4287 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
4289 def _value_sanitize(self, value):
4290 value = super(NumericString, self)._value_sanitize(value)
4291 if not frozenset(value) <= self._allowable_chars:
4292 raise DecodeError("non-numeric value")
4296 PrintableStringState = namedtuple(
4297 "PrintableStringState",
4298 OctetStringState._fields + ("allowable_chars",),
4303 class PrintableString(AllowableCharsMixin, CommonString):
4306 Its value is properly sanitized: see X.680 41.4 table 10.
4308 >>> PrintableString().allowable_chars
4309 frozenset([' ', "'", ..., 'z'])
4310 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4311 PrintableString PrintableString foo*bar
4312 >>> obj.allow_asterisk, obj.allow_ampersand
4316 tag_default = tag_encode(19)
4318 asn1_type_name = "PrintableString"
4319 _allowable_chars = frozenset(
4320 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4322 _asterisk = frozenset("*".encode("ascii"))
4323 _ampersand = frozenset("&".encode("ascii"))
4335 allow_asterisk=False,
4336 allow_ampersand=False,
4339 :param allow_asterisk: allow asterisk character
4340 :param allow_ampersand: allow ampersand character
4343 self._allowable_chars |= self._asterisk
4345 self._allowable_chars |= self._ampersand
4346 super(PrintableString, self).__init__(
4347 value, bounds, impl, expl, default, optional, _decoded, ctx,
4351 def allow_asterisk(self):
4352 """Is asterisk character allowed?
4354 return self._asterisk <= self._allowable_chars
4357 def allow_ampersand(self):
4358 """Is ampersand character allowed?
4360 return self._ampersand <= self._allowable_chars
4362 def _value_sanitize(self, value):
4363 value = super(PrintableString, self)._value_sanitize(value)
4364 if not frozenset(value) <= self._allowable_chars:
4365 raise DecodeError("non-printable value")
4368 def __getstate__(self):
4369 return PrintableStringState(
4370 *super(PrintableString, self).__getstate__(),
4371 **{"allowable_chars": self._allowable_chars}
4374 def __setstate__(self, state):
4375 super(PrintableString, self).__setstate__(state)
4376 self._allowable_chars = state.allowable_chars
4387 return self.__class__(
4390 (self._bound_min, self._bound_max)
4391 if bounds is None else bounds
4393 impl=self.tag if impl is None else impl,
4394 expl=self._expl if expl is None else expl,
4395 default=self.default if default is None else default,
4396 optional=self.optional if optional is None else optional,
4397 allow_asterisk=self.allow_asterisk,
4398 allow_ampersand=self.allow_ampersand,
4402 class TeletexString(CommonString):
4404 tag_default = tag_encode(20)
4406 asn1_type_name = "TeletexString"
4409 class T61String(TeletexString):
4411 asn1_type_name = "T61String"
4414 class VideotexString(CommonString):
4416 tag_default = tag_encode(21)
4417 encoding = "iso-8859-1"
4418 asn1_type_name = "VideotexString"
4421 class IA5String(CommonString):
4423 tag_default = tag_encode(22)
4425 asn1_type_name = "IA5"
4428 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4429 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4430 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4433 class VisibleString(CommonString):
4435 tag_default = tag_encode(26)
4437 asn1_type_name = "VisibleString"
4440 UTCTimeState = namedtuple(
4442 OctetStringState._fields + ("ber_raw",),
4447 def str_to_time_fractions(value):
4449 year, v = (v // 10**10), (v % 10**10)
4450 month, v = (v // 10**8), (v % 10**8)
4451 day, v = (v // 10**6), (v % 10**6)
4452 hour, v = (v // 10**4), (v % 10**4)
4453 minute, second = (v // 100), (v % 100)
4454 return year, month, day, hour, minute, second
4457 class UTCTime(VisibleString):
4458 """``UTCTime`` datetime type
4460 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4461 UTCTime UTCTime 2017-09-30T22:07:50
4467 datetime.datetime(2017, 9, 30, 22, 7, 50)
4468 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4469 datetime.datetime(1957, 9, 30, 22, 7, 50)
4471 If BER encoded value was met, then ``ber_raw`` attribute will hold
4472 its raw representation.
4476 Pay attention that UTCTime can not hold full year, so all years
4477 having < 50 years are treated as 20xx, 19xx otherwise, according
4478 to X.509 recommendation.
4482 No strict validation of UTC offsets are made, but very crude:
4484 * minutes are not exceeding 60
4485 * offset value is not exceeding 14 hours
4487 __slots__ = ("ber_raw",)
4488 tag_default = tag_encode(23)
4490 asn1_type_name = "UTCTime"
4491 evgen_mode_skip_value = False
4501 bounds=None, # dummy argument, workability for OctetString.decode
4505 :param value: set the value. Either datetime type, or
4506 :py:class:`pyderasn.UTCTime` object
4507 :param bytes impl: override default tag with ``IMPLICIT`` one
4508 :param bytes expl: override default tag with ``EXPLICIT`` one
4509 :param default: set default value. Type same as in ``value``
4510 :param bool optional: is object ``OPTIONAL`` in sequence
4512 super(UTCTime, self).__init__(
4513 None, None, impl, expl, None, optional, _decoded, ctx,
4517 if value is not None:
4518 self._value, self.ber_raw = self._value_sanitize(value, ctx)
4519 self.ber_encoded = self.ber_raw is not None
4520 if default is not None:
4521 default, _ = self._value_sanitize(default)
4522 self.default = self.__class__(
4527 if self._value is None:
4528 self._value = default
4530 self.optional = optional
4532 def _strptime_bered(self, value):
4533 year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
4536 raise ValueError("no timezone")
4537 year += 2000 if year < 50 else 1900
4538 decoded = datetime(year, month, day, hour, minute)
4540 if value[-1] == "Z":
4544 raise ValueError("invalid UTC offset")
4545 if value[-5] == "-":
4547 elif value[-5] == "+":
4550 raise ValueError("invalid UTC offset")
4551 v = pureint(value[-4:])
4552 offset, v = (60 * (v % 100)), v // 100
4554 raise ValueError("invalid UTC offset minutes")
4556 if offset > 14 * 3600:
4557 raise ValueError("too big UTC offset")
4561 return offset, decoded
4563 raise ValueError("invalid UTC offset seconds")
4564 seconds = pureint(value)
4566 raise ValueError("invalid seconds value")
4567 return offset, decoded + timedelta(seconds=seconds)
4569 def _strptime(self, value):
4570 # datetime.strptime's format: %y%m%d%H%M%SZ
4571 if len(value) != LEN_YYMMDDHHMMSSZ:
4572 raise ValueError("invalid UTCTime length")
4573 if value[-1] != "Z":
4574 raise ValueError("non UTC timezone")
4575 year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
4576 year += 2000 if year < 50 else 1900
4577 return datetime(year, month, day, hour, minute, second)
4579 def _dt_sanitize(self, value):
4580 if value.year < 1950 or value.year > 2049:
4581 raise ValueError("UTCTime can hold only 1950-2049 years")
4582 return value.replace(microsecond=0)
4584 def _value_sanitize(self, value, ctx=None):
4585 if value.__class__ == binary_type:
4587 value_decoded = value.decode("ascii")
4588 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4589 raise DecodeError("invalid UTCTime encoding: %r" % err)
4592 return self._strptime(value_decoded), None
4593 except (TypeError, ValueError) as _err:
4595 if (ctx is not None) and ctx.get("bered", False):
4597 offset, _value = self._strptime_bered(value_decoded)
4598 _value = _value - timedelta(seconds=offset)
4599 return self._dt_sanitize(_value), value
4600 except (TypeError, ValueError, OverflowError) as _err:
4603 "invalid %s format: %r" % (self.asn1_type_name, err),
4604 klass=self.__class__,
4606 if isinstance(value, self.__class__):
4607 return value._value, None
4608 if value.__class__ == datetime:
4609 return self._dt_sanitize(value), None
4610 raise InvalidValueType((self.__class__, datetime))
4612 def _pp_value(self):
4614 value = self._value.isoformat()
4615 if self.ber_encoded:
4616 value += " (%s)" % self.ber_raw
4619 def __unicode__(self):
4621 value = self._value.isoformat()
4622 if self.ber_encoded:
4623 value += " (%s)" % self.ber_raw
4625 return text_type(self._pp_value())
4627 def __getstate__(self):
4628 return UTCTimeState(
4629 *super(UTCTime, self).__getstate__(),
4630 **{"ber_raw": self.ber_raw}
4633 def __setstate__(self, state):
4634 super(UTCTime, self).__setstate__(state)
4635 self.ber_raw = state.ber_raw
4637 def __bytes__(self):
4638 self._assert_ready()
4639 return self._encode_time()
4641 def __eq__(self, their):
4642 if their.__class__ == binary_type:
4643 return self._encode_time() == their
4644 if their.__class__ == datetime:
4645 return self.todatetime() == their
4646 if not isinstance(their, self.__class__):
4649 self._value == their._value and
4650 self.tag == their.tag and
4651 self._expl == their._expl
4654 def _encode_time(self):
4655 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4658 self._assert_ready()
4659 value = self._encode_time()
4660 return b"".join((self.tag, len_encode(len(value)), value))
4662 def _encode_cer(self, writer):
4663 write_full(writer, self._encode())
4665 def todatetime(self):
4669 return pp_console_row(next(self.pps()))
4671 def pps(self, decode_path=()):
4674 asn1_type_name=self.asn1_type_name,
4675 obj_name=self.__class__.__name__,
4676 decode_path=decode_path,
4677 value=self._pp_value(),
4678 optional=self.optional,
4679 default=self == self.default,
4680 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4681 expl=None if self._expl is None else tag_decode(self._expl),
4686 expl_offset=self.expl_offset if self.expled else None,
4687 expl_tlen=self.expl_tlen if self.expled else None,
4688 expl_llen=self.expl_llen if self.expled else None,
4689 expl_vlen=self.expl_vlen if self.expled else None,
4690 expl_lenindef=self.expl_lenindef,
4691 ber_encoded=self.ber_encoded,
4694 for pp in self.pps_lenindef(decode_path):
4698 class GeneralizedTime(UTCTime):
4699 """``GeneralizedTime`` datetime type
4701 This type is similar to :py:class:`pyderasn.UTCTime`.
4703 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4704 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4706 '20170930220750.000123Z'
4707 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4708 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4712 Only microsecond fractions are supported in DER encoding.
4713 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4714 higher precision values.
4718 BER encoded data can loss information (accuracy) during decoding
4719 because of float transformations.
4723 Local times (without explicit timezone specification) are treated
4724 as UTC one, no transformations are made.
4728 Zero year is unsupported.
4731 tag_default = tag_encode(24)
4732 asn1_type_name = "GeneralizedTime"
4734 def _dt_sanitize(self, value):
4737 def _strptime_bered(self, value):
4738 if len(value) < 4 + 3 * 2:
4739 raise ValueError("invalid GeneralizedTime")
4740 year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
4741 decoded = datetime(year, month, day, hour)
4742 offset, value = 0, value[10:]
4744 return offset, decoded
4745 if value[-1] == "Z":
4748 for char, sign in (("-", -1), ("+", 1)):
4749 idx = value.rfind(char)
4752 offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
4753 v = pureint(offset_raw)
4754 if len(offset_raw) == 4:
4755 offset, v = (60 * (v % 100)), v // 100
4757 raise ValueError("invalid UTC offset minutes")
4758 elif len(offset_raw) == 2:
4761 raise ValueError("invalid UTC offset")
4763 if offset > 14 * 3600:
4764 raise ValueError("too big UTC offset")
4768 return offset, decoded
4769 if value[0] in DECIMAL_SIGNS:
4771 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4774 raise ValueError("stripped minutes")
4775 decoded += timedelta(seconds=60 * pureint(value[:2]))
4778 return offset, decoded
4779 if value[0] in DECIMAL_SIGNS:
4781 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4784 raise ValueError("stripped seconds")
4785 decoded += timedelta(seconds=pureint(value[:2]))
4788 return offset, decoded
4789 if value[0] not in DECIMAL_SIGNS:
4790 raise ValueError("invalid format after seconds")
4792 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4795 def _strptime(self, value):
4797 if l == LEN_YYYYMMDDHHMMSSZ:
4798 # datetime.strptime's format: %Y%m%d%H%M%SZ
4799 if value[-1] != "Z":
4800 raise ValueError("non UTC timezone")
4801 return datetime(*str_to_time_fractions(value[:-1]))
4802 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4803 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4804 if value[-1] != "Z":
4805 raise ValueError("non UTC timezone")
4806 if value[14] != ".":
4807 raise ValueError("no fractions separator")
4810 raise ValueError("trailing zero")
4813 raise ValueError("only microsecond fractions are supported")
4814 us = pureint(us + ("0" * (6 - us_len)))
4815 year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
4816 return datetime(year, month, day, hour, minute, second, us)
4817 raise ValueError("invalid GeneralizedTime length")
4819 def _encode_time(self):
4821 encoded = value.strftime("%Y%m%d%H%M%S")
4822 if value.microsecond > 0:
4823 encoded += (".%06d" % value.microsecond).rstrip("0")
4824 return (encoded + "Z").encode("ascii")
4827 class GraphicString(CommonString):
4829 tag_default = tag_encode(25)
4830 encoding = "iso-8859-1"
4831 asn1_type_name = "GraphicString"
4834 class ISO646String(VisibleString):
4836 asn1_type_name = "ISO646String"
4839 class GeneralString(CommonString):
4841 tag_default = tag_encode(27)
4842 encoding = "iso-8859-1"
4843 asn1_type_name = "GeneralString"
4846 class UniversalString(CommonString):
4848 tag_default = tag_encode(28)
4849 encoding = "utf-32-be"
4850 asn1_type_name = "UniversalString"
4853 class BMPString(CommonString):
4855 tag_default = tag_encode(30)
4856 encoding = "utf-16-be"
4857 asn1_type_name = "BMPString"
4860 ChoiceState = namedtuple(
4862 BasicState._fields + ("specs", "value",),
4868 """``CHOICE`` special type
4872 class GeneralName(Choice):
4874 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4875 ("dNSName", IA5String(impl=tag_ctxp(2))),
4878 >>> gn = GeneralName()
4880 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4881 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4882 >>> gn["dNSName"] = IA5String("bar.baz")
4883 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4884 >>> gn["rfc822Name"]
4887 [2] IA5String IA5 bar.baz
4890 >>> gn.value == gn["dNSName"]
4893 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4895 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4896 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4898 __slots__ = ("specs",)
4900 asn1_type_name = "CHOICE"
4913 :param value: set the value. Either ``(choice, value)`` tuple, or
4914 :py:class:`pyderasn.Choice` object
4915 :param bytes impl: can not be set, do **not** use it
4916 :param bytes expl: override default tag with ``EXPLICIT`` one
4917 :param default: set default value. Type same as in ``value``
4918 :param bool optional: is object ``OPTIONAL`` in sequence
4920 if impl is not None:
4921 raise ValueError("no implicit tag allowed for CHOICE")
4922 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4924 schema = getattr(self, "schema", ())
4925 if len(schema) == 0:
4926 raise ValueError("schema must be specified")
4928 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
4931 if value is not None:
4932 self._value = self._value_sanitize(value)
4933 if default is not None:
4934 default_value = self._value_sanitize(default)
4935 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4936 default_obj.specs = self.specs
4937 default_obj._value = default_value
4938 self.default = default_obj
4940 self._value = copy(default_obj._value)
4941 if self._expl is not None:
4942 tag_class, _, tag_num = tag_decode(self._expl)
4943 self._tag_order = (tag_class, tag_num)
4945 def _value_sanitize(self, value):
4946 if (value.__class__ == tuple) and len(value) == 2:
4948 spec = self.specs.get(choice)
4950 raise ObjUnknown(choice)
4951 if not isinstance(obj, spec.__class__):
4952 raise InvalidValueType((spec,))
4953 return (choice, spec(obj))
4954 if isinstance(value, self.__class__):
4956 raise InvalidValueType((self.__class__, tuple))
4960 return self._value is not None and self._value[1].ready
4964 return self.expl_lenindef or (
4965 (self._value is not None) and
4966 self._value[1].bered
4969 def __getstate__(self):
4987 def __setstate__(self, state):
4988 super(Choice, self).__setstate__(state)
4989 self.specs = state.specs
4990 self._value = state.value
4992 def __eq__(self, their):
4993 if (their.__class__ == tuple) and len(their) == 2:
4994 return self._value == their
4995 if not isinstance(their, self.__class__):
4998 self.specs == their.specs and
4999 self._value == their._value
5009 return self.__class__(
5012 expl=self._expl if expl is None else expl,
5013 default=self.default if default is None else default,
5014 optional=self.optional if optional is None else optional,
5019 """Name of the choice
5021 self._assert_ready()
5022 return self._value[0]
5026 """Value of underlying choice
5028 self._assert_ready()
5029 return self._value[1]
5032 def tag_order(self):
5033 self._assert_ready()
5034 return self._value[1].tag_order if self._tag_order is None else self._tag_order
5037 def tag_order_cer(self):
5038 return min(v.tag_order_cer for v in itervalues(self.specs))
5040 def __getitem__(self, key):
5041 if key not in self.specs:
5042 raise ObjUnknown(key)
5043 if self._value is None:
5045 choice, value = self._value
5050 def __setitem__(self, key, value):
5051 spec = self.specs.get(key)
5053 raise ObjUnknown(key)
5054 if not isinstance(value, spec.__class__):
5055 raise InvalidValueType((spec.__class__,))
5056 self._value = (key, spec(value))
5064 return self._value[1].decoded if self.ready else False
5067 self._assert_ready()
5068 return self._value[1].encode()
5070 def _encode_cer(self, writer):
5071 self._assert_ready()
5072 self._value[1].encode_cer(writer)
5074 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5075 for choice, spec in iteritems(self.specs):
5076 sub_decode_path = decode_path + (choice,)
5082 decode_path=sub_decode_path,
5085 _ctx_immutable=False,
5092 klass=self.__class__,
5093 decode_path=decode_path,
5096 if tag_only: # pragma: no cover
5100 for _decode_path, value, tail in spec.decode_evgen(
5104 decode_path=sub_decode_path,
5106 _ctx_immutable=False,
5108 yield _decode_path, value, tail
5110 _, value, tail = next(spec.decode_evgen(
5114 decode_path=sub_decode_path,
5116 _ctx_immutable=False,
5119 obj = self.__class__(
5122 default=self.default,
5123 optional=self.optional,
5124 _decoded=(offset, 0, value.fulllen),
5126 obj._value = (choice, value)
5127 yield decode_path, obj, tail
5130 value = pp_console_row(next(self.pps()))
5132 value = "%s[%r]" % (value, self.value)
5135 def pps(self, decode_path=()):
5138 asn1_type_name=self.asn1_type_name,
5139 obj_name=self.__class__.__name__,
5140 decode_path=decode_path,
5141 value=self.choice if self.ready else None,
5142 optional=self.optional,
5143 default=self == self.default,
5144 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5145 expl=None if self._expl is None else tag_decode(self._expl),
5150 expl_lenindef=self.expl_lenindef,
5154 yield self.value.pps(decode_path=decode_path + (self.choice,))
5155 for pp in self.pps_lenindef(decode_path):
5159 class PrimitiveTypes(Choice):
5160 """Predefined ``CHOICE`` for all generic primitive types
5162 It could be useful for general decoding of some unspecified values:
5164 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
5165 OCTET STRING 3 bytes 666f6f
5166 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
5170 schema = tuple((klass.__name__, klass()) for klass in (
5194 AnyState = namedtuple(
5196 BasicState._fields + ("value", "defined"),
5202 """``ANY`` special type
5204 >>> Any(Integer(-123))
5205 ANY INTEGER -123 (0X:7B)
5206 >>> a = Any(OctetString(b"hello world").encode())
5207 ANY 040b68656c6c6f20776f726c64
5208 >>> hexenc(bytes(a))
5209 b'0x040x0bhello world'
5211 __slots__ = ("defined",)
5212 tag_default = tag_encode(0)
5213 asn1_type_name = "ANY"
5223 :param value: set the value. Either any kind of pyderasn's
5224 **ready** object, or bytes. Pay attention that
5225 **no** validation is performed if raw binary value
5226 is valid TLV, except just tag decoding
5227 :param bytes expl: override default tag with ``EXPLICIT`` one
5228 :param bool optional: is object ``OPTIONAL`` in sequence
5230 super(Any, self).__init__(None, expl, None, optional, _decoded)
5234 value = self._value_sanitize(value)
5236 if self._expl is None:
5237 if value.__class__ == binary_type:
5238 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5240 tag_class, tag_num = value.tag_order
5242 tag_class, _, tag_num = tag_decode(self._expl)
5243 self._tag_order = (tag_class, tag_num)
5246 def _value_sanitize(self, value):
5247 if value.__class__ == binary_type:
5249 raise ValueError("Any value can not be empty")
5251 if isinstance(value, self.__class__):
5253 if not isinstance(value, Obj):
5254 raise InvalidValueType((self.__class__, Obj, binary_type))
5259 return self._value is not None
5262 def tag_order(self):
5263 self._assert_ready()
5264 return self._tag_order
5268 if self.expl_lenindef or self.lenindef:
5270 if self.defined is None:
5272 return self.defined[1].bered
5274 def __getstate__(self):
5292 def __setstate__(self, state):
5293 super(Any, self).__setstate__(state)
5294 self._value = state.value
5295 self.defined = state.defined
5297 def __eq__(self, their):
5298 if their.__class__ == binary_type:
5299 if self._value.__class__ == binary_type:
5300 return self._value == their
5301 return self._value.encode() == their
5302 if issubclass(their.__class__, Any):
5303 if self.ready and their.ready:
5304 return bytes(self) == bytes(their)
5305 return self.ready == their.ready
5314 return self.__class__(
5316 expl=self._expl if expl is None else expl,
5317 optional=self.optional if optional is None else optional,
5320 def __bytes__(self):
5321 self._assert_ready()
5323 if value.__class__ == binary_type:
5325 return self._value.encode()
5332 self._assert_ready()
5334 if value.__class__ == binary_type:
5336 return value.encode()
5338 def _encode_cer(self, writer):
5339 self._assert_ready()
5341 if value.__class__ == binary_type:
5342 write_full(writer, value)
5344 value.encode_cer(writer)
5346 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5348 t, tlen, lv = tag_strip(tlv)
5349 except DecodeError as err:
5350 raise err.__class__(
5352 klass=self.__class__,
5353 decode_path=decode_path,
5357 l, llen, v = len_decode(lv)
5358 except LenIndefForm as err:
5359 if not ctx.get("bered", False):
5360 raise err.__class__(
5362 klass=self.__class__,
5363 decode_path=decode_path,
5366 llen, vlen, v = 1, 0, lv[1:]
5367 sub_offset = offset + tlen + llen
5369 while v[:EOC_LEN].tobytes() != EOC:
5370 chunk, v = Any().decode(
5373 decode_path=decode_path + (str(chunk_i),),
5376 _ctx_immutable=False,
5378 vlen += chunk.tlvlen
5379 sub_offset += chunk.tlvlen
5381 tlvlen = tlen + llen + vlen + EOC_LEN
5382 obj = self.__class__(
5383 value=None if evgen_mode else tlv[:tlvlen].tobytes(),
5385 optional=self.optional,
5386 _decoded=(offset, 0, tlvlen),
5389 obj.tag = t.tobytes()
5390 yield decode_path, obj, v[EOC_LEN:]
5392 except DecodeError as err:
5393 raise err.__class__(
5395 klass=self.__class__,
5396 decode_path=decode_path,
5400 raise NotEnoughData(
5401 "encoded length is longer than data",
5402 klass=self.__class__,
5403 decode_path=decode_path,
5406 tlvlen = tlen + llen + l
5407 v, tail = tlv[:tlvlen], v[l:]
5408 obj = self.__class__(
5409 value=None if evgen_mode else v.tobytes(),
5411 optional=self.optional,
5412 _decoded=(offset, 0, tlvlen),
5414 obj.tag = t.tobytes()
5415 yield decode_path, obj, tail
5418 return pp_console_row(next(self.pps()))
5420 def pps(self, decode_path=()):
5424 elif value.__class__ == binary_type:
5430 asn1_type_name=self.asn1_type_name,
5431 obj_name=self.__class__.__name__,
5432 decode_path=decode_path,
5434 blob=self._value if self._value.__class__ == binary_type else None,
5435 optional=self.optional,
5436 default=self == self.default,
5437 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5438 expl=None if self._expl is None else tag_decode(self._expl),
5443 expl_offset=self.expl_offset if self.expled else None,
5444 expl_tlen=self.expl_tlen if self.expled else None,
5445 expl_llen=self.expl_llen if self.expled else None,
5446 expl_vlen=self.expl_vlen if self.expled else None,
5447 expl_lenindef=self.expl_lenindef,
5448 lenindef=self.lenindef,
5451 defined_by, defined = self.defined or (None, None)
5452 if defined_by is not None:
5454 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5456 for pp in self.pps_lenindef(decode_path):
5460 ########################################################################
5461 # ASN.1 constructed types
5462 ########################################################################
5464 def get_def_by_path(defines_by_path, sub_decode_path):
5465 """Get define by decode path
5467 for path, define in defines_by_path:
5468 if len(path) != len(sub_decode_path):
5470 for p1, p2 in zip(path, sub_decode_path):
5471 if (not p1 is any) and (p1 != p2):
5477 def abs_decode_path(decode_path, rel_path):
5478 """Create an absolute decode path from current and relative ones
5480 :param decode_path: current decode path, starting point. Tuple of strings
5481 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5482 If first tuple's element is "/", then treat it as
5483 an absolute path, ignoring ``decode_path`` as
5484 starting point. Also this tuple can contain ".."
5485 elements, stripping the leading element from
5488 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5489 ("foo", "bar", "baz", "whatever")
5490 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5492 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5495 if rel_path[0] == "/":
5497 if rel_path[0] == "..":
5498 return abs_decode_path(decode_path[:-1], rel_path[1:])
5499 return decode_path + rel_path
5502 SequenceState = namedtuple(
5504 BasicState._fields + ("specs", "value",),
5509 class Sequence(Obj):
5510 """``SEQUENCE`` structure type
5512 You have to make specification of sequence::
5514 class Extension(Sequence):
5516 ("extnID", ObjectIdentifier()),
5517 ("critical", Boolean(default=False)),
5518 ("extnValue", OctetString()),
5521 Then, you can work with it as with dictionary.
5523 >>> ext = Extension()
5524 >>> Extension().specs
5526 ('extnID', OBJECT IDENTIFIER),
5527 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5528 ('extnValue', OCTET STRING),
5530 >>> ext["extnID"] = "1.2.3"
5531 Traceback (most recent call last):
5532 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5533 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5535 You can determine if sequence is ready to be encoded:
5540 Traceback (most recent call last):
5541 pyderasn.ObjNotReady: object is not ready: extnValue
5542 >>> ext["extnValue"] = OctetString(b"foobar")
5546 Value you want to assign, must have the same **type** as in
5547 corresponding specification, but it can have different tags,
5548 optional/default attributes -- they will be taken from specification
5551 class TBSCertificate(Sequence):
5553 ("version", Version(expl=tag_ctxc(0), default="v1")),
5556 >>> tbs = TBSCertificate()
5557 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5559 Assign ``None`` to remove value from sequence.
5561 You can set values in Sequence during its initialization:
5563 >>> AlgorithmIdentifier((
5564 ("algorithm", ObjectIdentifier("1.2.3")),
5565 ("parameters", Any(Null()))
5567 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5569 You can determine if value exists/set in the sequence and take its value:
5571 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5574 OBJECT IDENTIFIER 1.2.3
5576 But pay attention that if value has default, then it won't be (not
5577 in) in the sequence (because ``DEFAULT`` must not be encoded in
5578 DER), but you can read its value:
5580 >>> "critical" in ext, ext["critical"]
5581 (False, BOOLEAN False)
5582 >>> ext["critical"] = Boolean(True)
5583 >>> "critical" in ext, ext["critical"]
5584 (True, BOOLEAN True)
5586 All defaulted values are always optional.
5588 .. _allow_default_values_ctx:
5590 DER prohibits default value encoding and will raise an error if
5591 default value is unexpectedly met during decode.
5592 If :ref:`bered <bered_ctx>` context option is set, then no error
5593 will be raised, but ``bered`` attribute set. You can disable strict
5594 defaulted values existence validation by setting
5595 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5599 Check for default value existence is not performed in
5600 ``evgen_mode``, because previously decoded values are not stored
5601 in memory, to be able to compare them.
5603 Two sequences are equal if they have equal specification (schema),
5604 implicit/explicit tagging and the same values.
5606 __slots__ = ("specs",)
5607 tag_default = tag_encode(form=TagFormConstructed, num=16)
5608 asn1_type_name = "SEQUENCE"
5620 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5622 schema = getattr(self, "schema", ())
5624 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
5627 if value is not None:
5628 if issubclass(value.__class__, Sequence):
5629 self._value = value._value
5630 elif hasattr(value, "__iter__"):
5631 for seq_key, seq_value in value:
5632 self[seq_key] = seq_value
5634 raise InvalidValueType((Sequence,))
5635 if default is not None:
5636 if not issubclass(default.__class__, Sequence):
5637 raise InvalidValueType((Sequence,))
5638 default_value = default._value
5639 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5640 default_obj.specs = self.specs
5641 default_obj._value = default_value
5642 self.default = default_obj
5644 self._value = copy(default_obj._value)
5648 for name, spec in iteritems(self.specs):
5649 value = self._value.get(name)
5660 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5662 return any(value.bered for value in itervalues(self._value))
5664 def __getstate__(self):
5665 return SequenceState(
5679 {k: copy(v) for k, v in iteritems(self._value)},
5682 def __setstate__(self, state):
5683 super(Sequence, self).__setstate__(state)
5684 self.specs = state.specs
5685 self._value = state.value
5687 def __eq__(self, their):
5688 if not isinstance(their, self.__class__):
5691 self.specs == their.specs and
5692 self.tag == their.tag and
5693 self._expl == their._expl and
5694 self._value == their._value
5705 return self.__class__(
5708 impl=self.tag if impl is None else impl,
5709 expl=self._expl if expl is None else expl,
5710 default=self.default if default is None else default,
5711 optional=self.optional if optional is None else optional,
5714 def __contains__(self, key):
5715 return key in self._value
5717 def __setitem__(self, key, value):
5718 spec = self.specs.get(key)
5720 raise ObjUnknown(key)
5722 self._value.pop(key, None)
5724 if not isinstance(value, spec.__class__):
5725 raise InvalidValueType((spec.__class__,))
5726 value = spec(value=value)
5727 if spec.default is not None and value == spec.default:
5728 self._value.pop(key, None)
5730 self._value[key] = value
5732 def __getitem__(self, key):
5733 value = self._value.get(key)
5734 if value is not None:
5736 spec = self.specs.get(key)
5738 raise ObjUnknown(key)
5739 if spec.default is not None:
5743 def _values_for_encoding(self):
5744 for name, spec in iteritems(self.specs):
5745 value = self._value.get(name)
5749 raise ObjNotReady(name)
5753 v = b"".join(v.encode() for v in self._values_for_encoding())
5754 return b"".join((self.tag, len_encode(len(v)), v))
5756 def _encode_cer(self, writer):
5757 write_full(writer, self.tag + LENINDEF)
5758 for v in self._values_for_encoding():
5759 v.encode_cer(writer)
5760 write_full(writer, EOC)
5762 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
5764 t, tlen, lv = tag_strip(tlv)
5765 except DecodeError as err:
5766 raise err.__class__(
5768 klass=self.__class__,
5769 decode_path=decode_path,
5774 klass=self.__class__,
5775 decode_path=decode_path,
5778 if tag_only: # pragma: no cover
5782 ctx_bered = ctx.get("bered", False)
5784 l, llen, v = len_decode(lv)
5785 except LenIndefForm as err:
5787 raise err.__class__(
5789 klass=self.__class__,
5790 decode_path=decode_path,
5793 l, llen, v = 0, 1, lv[1:]
5795 except DecodeError as err:
5796 raise err.__class__(
5798 klass=self.__class__,
5799 decode_path=decode_path,
5803 raise NotEnoughData(
5804 "encoded length is longer than data",
5805 klass=self.__class__,
5806 decode_path=decode_path,
5810 v, tail = v[:l], v[l:]
5812 sub_offset = offset + tlen + llen
5815 ctx_allow_default_values = ctx.get("allow_default_values", False)
5816 for name, spec in iteritems(self.specs):
5817 if spec.optional and (
5818 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5822 sub_decode_path = decode_path + (name,)
5825 for _decode_path, value, v_tail in spec.decode_evgen(
5829 decode_path=sub_decode_path,
5831 _ctx_immutable=False,
5833 yield _decode_path, value, v_tail
5835 _, value, v_tail = next(spec.decode_evgen(
5839 decode_path=sub_decode_path,
5841 _ctx_immutable=False,
5844 except TagMismatch as err:
5845 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5849 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5850 if not evgen_mode and defined is not None:
5851 defined_by, defined_spec = defined
5852 if issubclass(value.__class__, SequenceOf):
5853 for i, _value in enumerate(value):
5854 sub_sub_decode_path = sub_decode_path + (
5856 DecodePathDefBy(defined_by),
5858 defined_value, defined_tail = defined_spec.decode(
5859 memoryview(bytes(_value)),
5861 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5862 if value.expled else (value.tlen + value.llen)
5865 decode_path=sub_sub_decode_path,
5867 _ctx_immutable=False,
5869 if len(defined_tail) > 0:
5872 klass=self.__class__,
5873 decode_path=sub_sub_decode_path,
5876 _value.defined = (defined_by, defined_value)
5878 defined_value, defined_tail = defined_spec.decode(
5879 memoryview(bytes(value)),
5881 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5882 if value.expled else (value.tlen + value.llen)
5885 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5887 _ctx_immutable=False,
5889 if len(defined_tail) > 0:
5892 klass=self.__class__,
5893 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5896 value.defined = (defined_by, defined_value)
5898 value_len = value.fulllen
5900 sub_offset += value_len
5903 if spec.default is not None and value == spec.default:
5904 # This will not work in evgen_mode
5905 if ctx_bered or ctx_allow_default_values:
5909 "DEFAULT value met",
5910 klass=self.__class__,
5911 decode_path=sub_decode_path,
5914 values[name] = value
5915 spec_defines = getattr(spec, "defines", ())
5916 if len(spec_defines) == 0:
5917 defines_by_path = ctx.get("defines_by_path", ())
5918 if len(defines_by_path) > 0:
5919 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5920 if spec_defines is not None and len(spec_defines) > 0:
5921 for rel_path, schema in spec_defines:
5922 defined = schema.get(value, None)
5923 if defined is not None:
5924 ctx.setdefault("_defines", []).append((
5925 abs_decode_path(sub_decode_path[:-1], rel_path),
5929 if v[:EOC_LEN].tobytes() != EOC:
5932 klass=self.__class__,
5933 decode_path=decode_path,
5941 klass=self.__class__,
5942 decode_path=decode_path,
5945 obj = self.__class__(
5949 default=self.default,
5950 optional=self.optional,
5951 _decoded=(offset, llen, vlen),
5954 obj.lenindef = lenindef
5955 obj.ber_encoded = ber_encoded
5956 yield decode_path, obj, tail
5959 value = pp_console_row(next(self.pps()))
5961 for name in self.specs:
5962 _value = self._value.get(name)
5965 cols.append("%s: %s" % (name, repr(_value)))
5966 return "%s[%s]" % (value, "; ".join(cols))
5968 def pps(self, decode_path=()):
5971 asn1_type_name=self.asn1_type_name,
5972 obj_name=self.__class__.__name__,
5973 decode_path=decode_path,
5974 optional=self.optional,
5975 default=self == self.default,
5976 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5977 expl=None if self._expl is None else tag_decode(self._expl),
5982 expl_offset=self.expl_offset if self.expled else None,
5983 expl_tlen=self.expl_tlen if self.expled else None,
5984 expl_llen=self.expl_llen if self.expled else None,
5985 expl_vlen=self.expl_vlen if self.expled else None,
5986 expl_lenindef=self.expl_lenindef,
5987 lenindef=self.lenindef,
5988 ber_encoded=self.ber_encoded,
5991 for name in self.specs:
5992 value = self._value.get(name)
5995 yield value.pps(decode_path=decode_path + (name,))
5996 for pp in self.pps_lenindef(decode_path):
6000 class Set(Sequence):
6001 """``SET`` structure type
6003 Its usage is identical to :py:class:`pyderasn.Sequence`.
6005 .. _allow_unordered_set_ctx:
6007 DER prohibits unordered values encoding and will raise an error
6008 during decode. If :ref:`bered <bered_ctx>` context option is set,
6009 then no error will occur. Also you can disable strict values
6010 ordering check by setting ``"allow_unordered_set": True``
6011 :ref:`context <ctx>` option.
6014 tag_default = tag_encode(form=TagFormConstructed, num=17)
6015 asn1_type_name = "SET"
6018 v = b"".join(value.encode() for value in sorted(
6019 self._values_for_encoding(),
6020 key=attrgetter("tag_order"),
6022 return b"".join((self.tag, len_encode(len(v)), v))
6024 def _encode_cer(self, writer):
6025 write_full(writer, self.tag + LENINDEF)
6027 self._values_for_encoding(),
6028 key=attrgetter("tag_order_cer"),
6030 v.encode_cer(writer)
6031 write_full(writer, EOC)
6033 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
6035 t, tlen, lv = tag_strip(tlv)
6036 except DecodeError as err:
6037 raise err.__class__(
6039 klass=self.__class__,
6040 decode_path=decode_path,
6045 klass=self.__class__,
6046 decode_path=decode_path,
6053 ctx_bered = ctx.get("bered", False)
6055 l, llen, v = len_decode(lv)
6056 except LenIndefForm as err:
6058 raise err.__class__(
6060 klass=self.__class__,
6061 decode_path=decode_path,
6064 l, llen, v = 0, 1, lv[1:]
6066 except DecodeError as err:
6067 raise err.__class__(
6069 klass=self.__class__,
6070 decode_path=decode_path,
6074 raise NotEnoughData(
6075 "encoded length is longer than data",
6076 klass=self.__class__,
6080 v, tail = v[:l], v[l:]
6082 sub_offset = offset + tlen + llen
6085 ctx_allow_default_values = ctx.get("allow_default_values", False)
6086 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6087 tag_order_prev = (0, 0)
6088 _specs_items = copy(self.specs)
6091 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6093 for name, spec in iteritems(_specs_items):
6094 sub_decode_path = decode_path + (name,)
6100 decode_path=sub_decode_path,
6103 _ctx_immutable=False,
6110 klass=self.__class__,
6111 decode_path=decode_path,
6115 for _decode_path, value, v_tail in spec.decode_evgen(
6119 decode_path=sub_decode_path,
6121 _ctx_immutable=False,
6123 yield _decode_path, value, v_tail
6125 _, value, v_tail = next(spec.decode_evgen(
6129 decode_path=sub_decode_path,
6131 _ctx_immutable=False,
6134 value_tag_order = value.tag_order
6135 value_len = value.fulllen
6136 if tag_order_prev >= value_tag_order:
6137 if ctx_bered or ctx_allow_unordered_set:
6141 "unordered " + self.asn1_type_name,
6142 klass=self.__class__,
6143 decode_path=sub_decode_path,
6146 if spec.default is None or value != spec.default:
6148 elif ctx_bered or ctx_allow_default_values:
6152 "DEFAULT value met",
6153 klass=self.__class__,
6154 decode_path=sub_decode_path,
6157 values[name] = value
6158 del _specs_items[name]
6159 tag_order_prev = value_tag_order
6160 sub_offset += value_len
6164 obj = self.__class__(
6168 default=self.default,
6169 optional=self.optional,
6170 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6173 if v[:EOC_LEN].tobytes() != EOC:
6176 klass=self.__class__,
6177 decode_path=decode_path,
6182 for name, spec in iteritems(self.specs):
6183 if name not in values and not spec.optional:
6185 "%s value is not ready" % name,
6186 klass=self.__class__,
6187 decode_path=decode_path,
6192 obj.ber_encoded = ber_encoded
6193 yield decode_path, obj, tail
6196 SequenceOfState = namedtuple(
6198 BasicState._fields + ("spec", "value", "bound_min", "bound_max"),
6203 class SequenceOf(Obj):
6204 """``SEQUENCE OF`` sequence type
6206 For that kind of type you must specify the object it will carry on
6207 (bounds are for example here, not required)::
6209 class Ints(SequenceOf):
6214 >>> ints.append(Integer(123))
6215 >>> ints.append(Integer(234))
6217 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
6218 >>> [int(i) for i in ints]
6220 >>> ints.append(Integer(345))
6221 Traceback (most recent call last):
6222 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
6225 >>> ints[1] = Integer(345)
6227 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
6229 Also you can initialize sequence with preinitialized values:
6231 >>> ints = Ints([Integer(123), Integer(234)])
6233 __slots__ = ("spec", "_bound_min", "_bound_max")
6234 tag_default = tag_encode(form=TagFormConstructed, num=16)
6235 asn1_type_name = "SEQUENCE OF"
6248 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
6250 schema = getattr(self, "schema", None)
6252 raise ValueError("schema must be specified")
6254 self._bound_min, self._bound_max = getattr(
6258 ) if bounds is None else bounds
6260 if value is not None:
6261 self._value = self._value_sanitize(value)
6262 if default is not None:
6263 default_value = self._value_sanitize(default)
6264 default_obj = self.__class__(
6269 default_obj._value = default_value
6270 self.default = default_obj
6272 self._value = copy(default_obj._value)
6274 def _value_sanitize(self, value):
6275 if issubclass(value.__class__, SequenceOf):
6276 value = value._value
6277 elif hasattr(value, "__iter__"):
6280 raise InvalidValueType((self.__class__, iter))
6281 if not self._bound_min <= len(value) <= self._bound_max:
6282 raise BoundsError(self._bound_min, len(value), self._bound_max)
6284 if not isinstance(v, self.spec.__class__):
6285 raise InvalidValueType((self.spec.__class__,))
6290 return all(v.ready for v in self._value)
6294 if self.expl_lenindef or self.lenindef or self.ber_encoded:
6296 return any(v.bered for v in self._value)
6298 def __getstate__(self):
6299 return SequenceOfState(
6313 [copy(v) for v in self._value],
6318 def __setstate__(self, state):
6319 super(SequenceOf, self).__setstate__(state)
6320 self.spec = state.spec
6321 self._value = state.value
6322 self._bound_min = state.bound_min
6323 self._bound_max = state.bound_max
6325 def __eq__(self, their):
6326 if isinstance(their, self.__class__):
6328 self.spec == their.spec and
6329 self.tag == their.tag and
6330 self._expl == their._expl and
6331 self._value == their._value
6333 if hasattr(their, "__iter__"):
6334 return self._value == list(their)
6346 return self.__class__(
6350 (self._bound_min, self._bound_max)
6351 if bounds is None else bounds
6353 impl=self.tag if impl is None else impl,
6354 expl=self._expl if expl is None else expl,
6355 default=self.default if default is None else default,
6356 optional=self.optional if optional is None else optional,
6359 def __contains__(self, key):
6360 return key in self._value
6362 def append(self, value):
6363 if not isinstance(value, self.spec.__class__):
6364 raise InvalidValueType((self.spec.__class__,))
6365 if len(self._value) + 1 > self._bound_max:
6368 len(self._value) + 1,
6371 self._value.append(value)
6374 self._assert_ready()
6375 return iter(self._value)
6378 self._assert_ready()
6379 return len(self._value)
6381 def __setitem__(self, key, value):
6382 if not isinstance(value, self.spec.__class__):
6383 raise InvalidValueType((self.spec.__class__,))
6384 self._value[key] = self.spec(value=value)
6386 def __getitem__(self, key):
6387 return self._value[key]
6389 def _values_for_encoding(self):
6390 return iter(self._value)
6393 v = b"".join(v.encode() for v in self._values_for_encoding())
6394 return b"".join((self.tag, len_encode(len(v)), v))
6396 def _encode_cer(self, writer):
6397 write_full(writer, self.tag + LENINDEF)
6398 for v in self._values_for_encoding():
6399 v.encode_cer(writer)
6400 write_full(writer, EOC)
6410 ordering_check=False,
6413 t, tlen, lv = tag_strip(tlv)
6414 except DecodeError as err:
6415 raise err.__class__(
6417 klass=self.__class__,
6418 decode_path=decode_path,
6423 klass=self.__class__,
6424 decode_path=decode_path,
6431 ctx_bered = ctx.get("bered", False)
6433 l, llen, v = len_decode(lv)
6434 except LenIndefForm as err:
6436 raise err.__class__(
6438 klass=self.__class__,
6439 decode_path=decode_path,
6442 l, llen, v = 0, 1, lv[1:]
6444 except DecodeError as err:
6445 raise err.__class__(
6447 klass=self.__class__,
6448 decode_path=decode_path,
6452 raise NotEnoughData(
6453 "encoded length is longer than data",
6454 klass=self.__class__,
6455 decode_path=decode_path,
6459 v, tail = v[:l], v[l:]
6461 sub_offset = offset + tlen + llen
6464 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6465 value_prev = memoryview(v[:0])
6469 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6471 sub_decode_path = decode_path + (str(_value_count),)
6473 for _decode_path, value, v_tail in spec.decode_evgen(
6477 decode_path=sub_decode_path,
6479 _ctx_immutable=False,
6481 yield _decode_path, value, v_tail
6483 _, value, v_tail = next(spec.decode_evgen(
6487 decode_path=sub_decode_path,
6489 _ctx_immutable=False,
6492 value_len = value.fulllen
6494 if value_prev.tobytes() > v[:value_len].tobytes():
6495 if ctx_bered or ctx_allow_unordered_set:
6499 "unordered " + self.asn1_type_name,
6500 klass=self.__class__,
6501 decode_path=sub_decode_path,
6504 value_prev = v[:value_len]
6507 _value.append(value)
6508 sub_offset += value_len
6511 if evgen_mode and not self._bound_min <= _value_count <= self._bound_max:
6513 msg=str(BoundsError(self._bound_min, _value_count, self._bound_max)),
6514 klass=self.__class__,
6515 decode_path=decode_path,
6519 obj = self.__class__(
6520 value=None if evgen_mode else _value,
6522 bounds=(self._bound_min, self._bound_max),
6525 default=self.default,
6526 optional=self.optional,
6527 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6529 except BoundsError as err:
6532 klass=self.__class__,
6533 decode_path=decode_path,
6537 if v[:EOC_LEN].tobytes() != EOC:
6540 klass=self.__class__,
6541 decode_path=decode_path,
6546 obj.ber_encoded = ber_encoded
6547 yield decode_path, obj, tail
6551 pp_console_row(next(self.pps())),
6552 ", ".join(repr(v) for v in self._value),
6555 def pps(self, decode_path=()):
6558 asn1_type_name=self.asn1_type_name,
6559 obj_name=self.__class__.__name__,
6560 decode_path=decode_path,
6561 optional=self.optional,
6562 default=self == self.default,
6563 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6564 expl=None if self._expl is None else tag_decode(self._expl),
6569 expl_offset=self.expl_offset if self.expled else None,
6570 expl_tlen=self.expl_tlen if self.expled else None,
6571 expl_llen=self.expl_llen if self.expled else None,
6572 expl_vlen=self.expl_vlen if self.expled else None,
6573 expl_lenindef=self.expl_lenindef,
6574 lenindef=self.lenindef,
6575 ber_encoded=self.ber_encoded,
6578 for i, value in enumerate(self._value):
6579 yield value.pps(decode_path=decode_path + (str(i),))
6580 for pp in self.pps_lenindef(decode_path):
6584 class SetOf(SequenceOf):
6585 """``SET OF`` sequence type
6587 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6590 tag_default = tag_encode(form=TagFormConstructed, num=17)
6591 asn1_type_name = "SET OF"
6594 v = b"".join(sorted(v.encode() for v in self._values_for_encoding()))
6595 return b"".join((self.tag, len_encode(len(v)), v))
6597 def _encode_cer(self, writer):
6598 write_full(writer, self.tag + LENINDEF)
6599 for v in sorted(encode_cer(v) for v in self._values_for_encoding()):
6600 write_full(writer, v)
6601 write_full(writer, EOC)
6603 def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
6604 return super(SetOf, self)._decode(
6611 ordering_check=True,
6615 def obj_by_path(pypath): # pragma: no cover
6616 """Import object specified as string Python path
6618 Modules must be separated from classes/functions with ``:``.
6620 >>> obj_by_path("foo.bar:Baz")
6621 <class 'foo.bar.Baz'>
6622 >>> obj_by_path("foo.bar:Baz.boo")
6623 <classmethod 'foo.bar.Baz.boo'>
6625 mod, objs = pypath.rsplit(":", 1)
6626 from importlib import import_module
6627 obj = import_module(mod)
6628 for obj_name in objs.split("."):
6629 obj = getattr(obj, obj_name)
6633 def generic_decoder(): # pragma: no cover
6634 # All of this below is a big hack with self references
6635 choice = PrimitiveTypes()
6636 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6637 choice.specs["SetOf"] = SetOf(schema=choice)
6638 for i in six_xrange(31):
6639 choice.specs["SequenceOf%d" % i] = SequenceOf(
6643 choice.specs["Any"] = Any()
6645 # Class name equals to type name, to omit it from output
6646 class SEQUENCEOF(SequenceOf):
6654 with_decode_path=False,
6655 decode_path_only=(),
6657 def _pprint_pps(pps):
6659 if hasattr(pp, "_fields"):
6661 decode_path_only != () and
6662 pp.decode_path[:len(decode_path_only)] != decode_path_only
6665 if pp.asn1_type_name == Choice.asn1_type_name:
6667 pp_kwargs = pp._asdict()
6668 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6669 pp = _pp(**pp_kwargs)
6670 yield pp_console_row(
6675 with_colours=with_colours,
6676 with_decode_path=with_decode_path,
6677 decode_path_len_decrease=len(decode_path_only),
6679 for row in pp_console_blob(
6681 decode_path_len_decrease=len(decode_path_only),
6685 for row in _pprint_pps(pp):
6687 return "\n".join(_pprint_pps(obj.pps()))
6688 return SEQUENCEOF(), pprint_any
6691 def main(): # pragma: no cover
6693 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6694 parser.add_argument(
6698 help="Skip that number of bytes from the beginning",
6700 parser.add_argument(
6702 help="Python paths to dictionary with OIDs, comma separated",
6704 parser.add_argument(
6706 help="Python path to schema definition to use",
6708 parser.add_argument(
6709 "--defines-by-path",
6710 help="Python path to decoder's defines_by_path",
6712 parser.add_argument(
6714 action="store_true",
6715 help="Disallow BER encoding",
6717 parser.add_argument(
6718 "--print-decode-path",
6719 action="store_true",
6720 help="Print decode paths",
6722 parser.add_argument(
6723 "--decode-path-only",
6724 help="Print only specified decode path",
6726 parser.add_argument(
6728 action="store_true",
6729 help="Allow explicit tag out-of-bound",
6731 parser.add_argument(
6733 action="store_true",
6734 help="Turn on event generation mode",
6736 parser.add_argument(
6738 type=argparse.FileType("rb"),
6739 help="Path to BER/CER/DER file you want to decode",
6741 args = parser.parse_args()
6743 args.RAWFile.seek(args.skip)
6744 raw = memoryview(args.RAWFile.read())
6745 args.RAWFile.close()
6747 raw = file_mmaped(args.RAWFile)[args.skip:]
6749 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6750 if args.oids else ()
6753 schema = obj_by_path(args.schema)
6754 from functools import partial
6755 pprinter = partial(pprint, big_blobs=True)
6757 schema, pprinter = generic_decoder()
6759 "bered": not args.nobered,
6760 "allow_expl_oob": args.allow_expl_oob,
6762 if args.defines_by_path is not None:
6763 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6764 from os import environ
6768 with_colours=environ.get("NO_COLOR") is None,
6769 with_decode_path=args.print_decode_path,
6771 () if args.decode_path_only is None else
6772 tuple(args.decode_path_only.split(":"))
6776 for decode_path, obj, tail in schema().decode_evgen(raw, ctx=ctx):
6777 print(pprinter(obj, decode_path=decode_path))
6779 obj, tail = schema().decode(raw, ctx=ctx)
6780 print(pprinter(obj))
6782 print("\nTrailing data: %s" % hexenc(tail))
6785 if __name__ == "__main__":