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``
361 ASN.1 structures often have ANY and OCTET STRING fields, that are
362 DEFINED BY some previously met ObjectIdentifier. This library provides
363 ability to specify mapping between some OID and field that must be
364 decoded with specific specification.
371 :py:class:`pyderasn.ObjectIdentifier` field inside
372 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
373 necessary for decoding structures. For example, CMS (:rfc:`5652`)
376 class ContentInfo(Sequence):
378 ("contentType", ContentType(defines=((("content",), {
379 id_digestedData: DigestedData(),
380 id_signedData: SignedData(),
382 ("content", Any(expl=tag_ctxc(0))),
385 ``contentType`` field tells that it defines that ``content`` must be
386 decoded with ``SignedData`` specification, if ``contentType`` equals to
387 ``id-signedData``. The same applies to ``DigestedData``. If
388 ``contentType`` contains unknown OID, then no automatic decoding is
391 You can specify multiple fields, that will be autodecoded -- that is why
392 ``defines`` kwarg is a sequence. You can specify defined field
393 relatively or absolutely to current decode path. For example ``defines``
394 for AlgorithmIdentifier of X.509's
395 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
399 id_ecPublicKey: ECParameters(),
400 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
402 (("..", "subjectPublicKey"), {
403 id_rsaEncryption: RSAPublicKey(),
404 id_GostR3410_2001: OctetString(),
408 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
409 autodecode its parameters inside SPKI's algorithm and its public key
412 Following types can be automatically decoded (DEFINED BY):
414 * :py:class:`pyderasn.Any`
415 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
416 * :py:class:`pyderasn.OctetString`
417 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
418 ``Any``/``BitString``/``OctetString``-s
420 When any of those fields is automatically decoded, then ``.defined``
421 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
422 was defined, ``value`` contains corresponding decoded value. For example
423 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
425 .. _defines_by_path_ctx:
427 defines_by_path context option
428 ______________________________
430 Sometimes you either can not or do not want to explicitly set *defines*
431 in the schema. You can dynamically apply those definitions when calling
432 ``.decode()`` method.
434 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
435 value must be sequence of following tuples::
437 (decode_path, defines)
439 where ``decode_path`` is a tuple holding so-called decode path to the
440 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
441 ``defines``, holding exactly the same value as accepted in its
442 :ref:`keyword argument <defines>`.
444 For example, again for CMS, you want to automatically decode
445 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
446 structures it may hold. Also, automatically decode ``controlSequence``
449 content_info = ContentInfo().decod(data, ctx={"defines_by_path": (
452 ((("content",), {id_signedData: SignedData()}),),
457 DecodePathDefBy(id_signedData),
462 id_cct_PKIData: PKIData(),
463 id_cct_PKIResponse: PKIResponse(),
469 DecodePathDefBy(id_signedData),
472 DecodePathDefBy(id_cct_PKIResponse),
478 id_cmc_recipientNonce: RecipientNonce(),
479 id_cmc_senderNonce: SenderNonce(),
480 id_cmc_statusInfoV2: CMCStatusInfoV2(),
481 id_cmc_transactionId: TransactionId(),
486 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
487 First function is useful for path construction when some automatic
488 decoding is already done. ``any`` means literally any value it meet --
489 useful for SEQUENCE/SET OF-s.
496 By default PyDERASN accepts only DER encoded data. It always encodes to
497 DER. But you can optionally enable BER decoding with setting ``bered``
498 :ref:`context <ctx>` argument to True. Indefinite lengths and
499 constructed primitive types should be parsed successfully.
501 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
502 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
503 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``,
504 ``UTCTime``, ``GeneralizedTime`` can contain it.
505 * If object has an indefinite length encoding, then its ``lenindef``
506 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
507 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
509 * If object has an indefinite length encoded explicit tag, then
510 ``expl_lenindef`` is set to True.
511 * If object has either any of BER-related encoding (explicit tag
512 indefinite length, object's indefinite length, BER-encoding) or any
513 underlying component has that kind of encoding, then ``bered``
514 attribute is set to True. For example SignedData CMS can have
515 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
516 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
518 EOC (end-of-contents) token's length is taken in advance in object's
521 .. _allow_expl_oob_ctx:
523 Allow explicit tag out-of-bound
524 -------------------------------
526 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
527 one value, more than one object. If you set ``allow_expl_oob`` context
528 option to True, then no error will be raised and that invalid encoding
529 will be silently further processed. But pay attention that offsets and
530 lengths will be invalid in that case.
534 This option should be used only for skipping some decode errors, just
535 to see the decoded structure somehow.
539 .. autoclass:: pyderasn.Obj
547 .. autoclass:: pyderasn.Boolean
552 .. autoclass:: pyderasn.Integer
557 .. autoclass:: pyderasn.BitString
562 .. autoclass:: pyderasn.OctetString
567 .. autoclass:: pyderasn.Null
572 .. autoclass:: pyderasn.ObjectIdentifier
577 .. autoclass:: pyderasn.Enumerated
581 .. autoclass:: pyderasn.CommonString
585 .. autoclass:: pyderasn.NumericString
589 .. autoclass:: pyderasn.PrintableString
594 .. autoclass:: pyderasn.UTCTime
595 :members: __init__, todatetime
599 .. autoclass:: pyderasn.GeneralizedTime
606 .. autoclass:: pyderasn.Choice
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.hexenc
647 .. autofunction:: pyderasn.hexdec
648 .. autofunction:: pyderasn.tag_encode
649 .. autofunction:: pyderasn.tag_decode
650 .. autofunction:: pyderasn.tag_ctxp
651 .. autofunction:: pyderasn.tag_ctxc
652 .. autoclass:: pyderasn.DecodeError
654 .. autoclass:: pyderasn.NotEnoughData
655 .. autoclass:: pyderasn.ExceedingData
656 .. autoclass:: pyderasn.LenIndefForm
657 .. autoclass:: pyderasn.TagMismatch
658 .. autoclass:: pyderasn.InvalidLength
659 .. autoclass:: pyderasn.InvalidOID
660 .. autoclass:: pyderasn.ObjUnknown
661 .. autoclass:: pyderasn.ObjNotReady
662 .. autoclass:: pyderasn.InvalidValueType
663 .. autoclass:: pyderasn.BoundsError
670 You can decode DER/BER files using command line abilities::
672 $ python -m pyderasn --schema tests.test_crts:Certificate path/to/file
674 If there is no schema for your file, then you can try parsing it without,
675 but of course IMPLICIT tags will often make it impossible. But result is
676 good enough for the certificate above::
678 $ python -m pyderasn path/to/file
679 0 [1,3,1604] . >: SEQUENCE OF
680 4 [1,3,1453] . . >: SEQUENCE OF
681 8 [0,0, 5] . . . . >: [0] ANY
682 . . . . . A0:03:02:01:02
683 13 [1,1, 3] . . . . >: INTEGER 61595
684 18 [1,1, 13] . . . . >: SEQUENCE OF
685 20 [1,1, 9] . . . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
686 31 [1,1, 0] . . . . . . >: NULL
687 33 [1,3, 274] . . . . >: SEQUENCE OF
688 37 [1,1, 11] . . . . . . >: SET OF
689 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
690 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER 2.5.4.6
691 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
693 1409 [1,1, 50] . . . . . . >: SEQUENCE OF
694 1411 [1,1, 8] . . . . . . . . >: OBJECT IDENTIFIER 1.3.6.1.5.5.7.1.1
695 1421 [1,1, 38] . . . . . . . . >: OCTET STRING 38 bytes
696 . . . . . . . . . 30:24:30:22:06:08:2B:06:01:05:05:07:30:01:86:16
697 . . . . . . . . . 68:74:74:70:3A:2F:2F:6F:63:73:70:2E:69:70:73:63
698 . . . . . . . . . 61:2E:63:6F:6D:2F
699 1461 [1,1, 13] . . >: SEQUENCE OF
700 1463 [1,1, 9] . . . . >: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
701 1474 [1,1, 0] . . . . >: NULL
702 1476 [1,2, 129] . . >: BIT STRING 1024 bits
703 . . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
704 . . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
710 If you have got dictionaries with ObjectIdentifiers, like example one
711 from ``tests/test_crts.py``::
714 "1.2.840.113549.1.1.1": "id-rsaEncryption",
715 "1.2.840.113549.1.1.5": "id-sha1WithRSAEncryption",
717 "2.5.4.10": "id-at-organizationName",
718 "2.5.4.11": "id-at-organizationalUnitName",
721 then you can pass it to pretty printer to see human readable OIDs::
723 $ python -m pyderasn --oids tests.test_crts:stroid2name path/to/file
725 37 [1,1, 11] . . . . . . >: SET OF
726 39 [1,1, 9] . . . . . . . . >: SEQUENCE OF
727 41 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-countryName (2.5.4.6)
728 46 [1,1, 2] . . . . . . . . . . >: PrintableString PrintableString ES
729 50 [1,1, 18] . . . . . . >: SET OF
730 52 [1,1, 16] . . . . . . . . >: SEQUENCE OF
731 54 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-stateOrProvinceName (2.5.4.8)
732 59 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
733 70 [1,1, 18] . . . . . . >: SET OF
734 72 [1,1, 16] . . . . . . . . >: SEQUENCE OF
735 74 [1,1, 3] . . . . . . . . . . >: OBJECT IDENTIFIER id-at-localityName (2.5.4.7)
736 79 [1,1, 9] . . . . . . . . . . >: PrintableString PrintableString Barcelona
742 Each decoded element has so-called decode path: sequence of structure
743 names it is passing during the decode process. Each element has its own
744 unique path inside the whole ASN.1 tree. You can print it out with
745 ``--print-decode-path`` option::
747 $ python -m pyderasn --schema path.to:Certificate --print-decode-path path/to/file
748 0 [1,3,1604] Certificate SEQUENCE []
749 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE [tbsCertificate]
750 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL [tbsCertificate:version]
751 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595 [tbsCertificate:serialNumber]
752 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE [tbsCertificate:signature]
753 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5 [tbsCertificate:signature:algorithm]
754 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL [tbsCertificate:signature:parameters]
756 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence [tbsCertificate:issuer]
757 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF [tbsCertificate:issuer:rdnSequence]
758 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF [tbsCertificate:issuer:rdnSequence:0]
759 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE [tbsCertificate:issuer:rdnSequence:0:0]
760 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6 [tbsCertificate:issuer:rdnSequence:0:0:type]
761 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY [tbsCertificate:issuer:rdnSequence:0:0:value]
762 . . . . . . . 13:02:45:53
763 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]
766 Now you can print only the specified tree, for example signature algorithm::
768 $ python -m pyderasn --schema path.to:Certificate --decode-path-only tbsCertificate:signature path/to/file
769 18 [1,1, 13] AlgorithmIdentifier SEQUENCE
770 20 [1,1, 9] . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
771 31 [0,0, 2] . parameters: [UNIV 5] ANY OPTIONAL
775 from codecs import getdecoder
776 from codecs import getencoder
777 from collections import namedtuple
778 from collections import OrderedDict
779 from copy import copy
780 from datetime import datetime
781 from datetime import timedelta
782 from math import ceil
783 from string import ascii_letters
784 from string import digits
785 from sys import version_info
786 from unicodedata import category as unicat
788 from six import add_metaclass
789 from six import binary_type
790 from six import byte2int
791 from six import indexbytes
792 from six import int2byte
793 from six import integer_types
794 from six import iterbytes
795 from six import iteritems
796 from six import itervalues
798 from six import string_types
799 from six import text_type
800 from six import unichr as six_unichr
801 from six.moves import xrange as six_xrange
805 from termcolor import colored
806 except ImportError: # pragma: no cover
807 def colored(what, *args, **kwargs):
853 "TagClassApplication",
857 "TagFormConstructed",
868 TagClassUniversal = 0
869 TagClassApplication = 1 << 6
870 TagClassContext = 1 << 7
871 TagClassPrivate = 1 << 6 | 1 << 7
873 TagFormConstructed = 1 << 5
876 TagClassApplication: "APPLICATION ",
877 TagClassPrivate: "PRIVATE ",
878 TagClassUniversal: "UNIV ",
882 LENINDEF = b"\x80" # length indefinite mark
883 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
884 NAMEDTUPLE_KWARGS = {} if version_info < (3, 6) else {"module": __name__}
885 SET01 = frozenset("01")
886 DECIMALS = frozenset(digits)
891 if not set(value) <= DECIMALS:
892 raise ValueError("non-pure integer")
895 def fractions2float(fractions_raw):
896 pureint(fractions_raw)
897 return float("0." + fractions_raw)
900 ########################################################################
902 ########################################################################
904 class ASN1Error(ValueError):
908 class DecodeError(ASN1Error):
909 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
911 :param str msg: reason of decode failing
912 :param klass: optional exact DecodeError inherited class (like
913 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
914 :py:exc:`InvalidLength`)
915 :param decode_path: tuple of strings. It contains human
916 readable names of the fields through which
917 decoding process has passed
918 :param int offset: binary offset where failure happened
920 super(DecodeError, self).__init__()
923 self.decode_path = decode_path
929 "" if self.klass is None else self.klass.__name__,
931 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
932 if len(self.decode_path) > 0 else ""
934 ("(at %d)" % self.offset) if self.offset > 0 else "",
940 return "%s(%s)" % (self.__class__.__name__, self)
943 class NotEnoughData(DecodeError):
947 class ExceedingData(ASN1Error):
948 def __init__(self, nbytes):
949 super(ExceedingData, self).__init__()
953 return "%d trailing bytes" % self.nbytes
956 return "%s(%s)" % (self.__class__.__name__, self)
959 class LenIndefForm(DecodeError):
963 class TagMismatch(DecodeError):
967 class InvalidLength(DecodeError):
971 class InvalidOID(DecodeError):
975 class ObjUnknown(ASN1Error):
976 def __init__(self, name):
977 super(ObjUnknown, self).__init__()
981 return "object is unknown: %s" % self.name
984 return "%s(%s)" % (self.__class__.__name__, self)
987 class ObjNotReady(ASN1Error):
988 def __init__(self, name):
989 super(ObjNotReady, self).__init__()
993 return "object is not ready: %s" % self.name
996 return "%s(%s)" % (self.__class__.__name__, self)
999 class InvalidValueType(ASN1Error):
1000 def __init__(self, expected_types):
1001 super(InvalidValueType, self).__init__()
1002 self.expected_types = expected_types
1005 return "invalid value type, expected: %s" % ", ".join(
1006 [repr(t) for t in self.expected_types]
1010 return "%s(%s)" % (self.__class__.__name__, self)
1013 class BoundsError(ASN1Error):
1014 def __init__(self, bound_min, value, bound_max):
1015 super(BoundsError, self).__init__()
1016 self.bound_min = bound_min
1018 self.bound_max = bound_max
1021 return "unsatisfied bounds: %s <= %s <= %s" % (
1028 return "%s(%s)" % (self.__class__.__name__, self)
1031 ########################################################################
1033 ########################################################################
1035 _hexdecoder = getdecoder("hex")
1036 _hexencoder = getencoder("hex")
1040 """Binary data to hexadecimal string convert
1042 return _hexdecoder(data)[0]
1046 """Hexadecimal string to binary data convert
1048 return _hexencoder(data)[0].decode("ascii")
1051 def int_bytes_len(num, byte_len=8):
1054 return int(ceil(float(num.bit_length()) / byte_len))
1057 def zero_ended_encode(num):
1058 octets = bytearray(int_bytes_len(num, 7))
1060 octets[i] = num & 0x7F
1064 octets[i] = 0x80 | (num & 0x7F)
1067 return bytes(octets)
1070 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
1071 """Encode tag to binary form
1073 :param int num: tag's number
1074 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
1075 :py:data:`pyderasn.TagClassContext`,
1076 :py:data:`pyderasn.TagClassApplication`,
1077 :py:data:`pyderasn.TagClassPrivate`)
1078 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
1079 :py:data:`pyderasn.TagFormConstructed`)
1083 return int2byte(klass | form | num)
1084 # [XX|X|11111][1.......][1.......] ... [0.......]
1085 return int2byte(klass | form | 31) + zero_ended_encode(num)
1088 def tag_decode(tag):
1089 """Decode tag from binary form
1093 No validation is performed, assuming that it has already passed.
1095 It returns tuple with three integers, as
1096 :py:func:`pyderasn.tag_encode` accepts.
1098 first_octet = byte2int(tag)
1099 klass = first_octet & 0xC0
1100 form = first_octet & 0x20
1101 if first_octet & 0x1F < 0x1F:
1102 return (klass, form, first_octet & 0x1F)
1104 for octet in iterbytes(tag[1:]):
1107 return (klass, form, num)
1111 """Create CONTEXT PRIMITIVE tag
1113 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
1117 """Create CONTEXT CONSTRUCTED tag
1119 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
1122 def tag_strip(data):
1123 """Take off tag from the data
1125 :returns: (encoded tag, tag length, remaining data)
1128 raise NotEnoughData("no data at all")
1129 if byte2int(data) & 0x1F < 31:
1130 return data[:1], 1, data[1:]
1135 raise DecodeError("unfinished tag")
1136 if indexbytes(data, i) & 0x80 == 0:
1139 return data[:i], i, data[i:]
1145 octets = bytearray(int_bytes_len(l) + 1)
1146 octets[0] = 0x80 | (len(octets) - 1)
1147 for i in six_xrange(len(octets) - 1, 0, -1):
1148 octets[i] = l & 0xFF
1150 return bytes(octets)
1153 def len_decode(data):
1156 :returns: (decoded length, length's length, remaining data)
1157 :raises LenIndefForm: if indefinite form encoding is met
1160 raise NotEnoughData("no data at all")
1161 first_octet = byte2int(data)
1162 if first_octet & 0x80 == 0:
1163 return first_octet, 1, data[1:]
1164 octets_num = first_octet & 0x7F
1165 if octets_num + 1 > len(data):
1166 raise NotEnoughData("encoded length is longer than data")
1168 raise LenIndefForm()
1169 if byte2int(data[1:]) == 0:
1170 raise DecodeError("leading zeros")
1172 for v in iterbytes(data[1:1 + octets_num]):
1175 raise DecodeError("long form instead of short one")
1176 return l, 1 + octets_num, data[1 + octets_num:]
1179 ########################################################################
1181 ########################################################################
1183 class AutoAddSlots(type):
1184 def __new__(cls, name, bases, _dict):
1185 _dict["__slots__"] = _dict.get("__slots__", ())
1186 return type.__new__(cls, name, bases, _dict)
1189 BasicState = namedtuple("BasicState", (
1201 ), **NAMEDTUPLE_KWARGS)
1204 @add_metaclass(AutoAddSlots)
1206 """Common ASN.1 object class
1208 All ASN.1 types are inherited from it. It has metaclass that
1209 automatically adds ``__slots__`` to all inherited classes.
1233 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1234 self._expl = getattr(self, "expl", None) if expl is None else expl
1235 if self.tag != self.tag_default and self._expl is not None:
1236 raise ValueError("implicit and explicit tags can not be set simultaneously")
1237 if default is not None:
1239 self.optional = optional
1240 self.offset, self.llen, self.vlen = _decoded
1242 self.expl_lenindef = False
1243 self.lenindef = False
1244 self.ber_encoded = False
1247 def ready(self): # pragma: no cover
1248 """Is object ready to be encoded?
1250 raise NotImplementedError()
1252 def _assert_ready(self):
1254 raise ObjNotReady(self.__class__.__name__)
1258 """Is either object or any elements inside is BER encoded?
1260 return self.expl_lenindef or self.lenindef or self.ber_encoded
1264 """Is object decoded?
1266 return (self.llen + self.vlen) > 0
1268 def __getstate__(self): # pragma: no cover
1269 """Used for making safe to be mutable pickleable copies
1271 raise NotImplementedError()
1273 def __setstate__(self, state):
1274 if state.version != __version__:
1275 raise ValueError("data is pickled by different PyDERASN version")
1276 self.tag = state.tag
1277 self._expl = state.expl
1278 self.default = state.default
1279 self.optional = state.optional
1280 self.offset = state.offset
1281 self.llen = state.llen
1282 self.vlen = state.vlen
1283 self.expl_lenindef = state.expl_lenindef
1284 self.lenindef = state.lenindef
1285 self.ber_encoded = state.ber_encoded
1289 """See :ref:`decoding`
1291 return len(self.tag)
1295 """See :ref:`decoding`
1297 return self.tlen + self.llen + self.vlen
1299 def __str__(self): # pragma: no cover
1300 return self.__bytes__() if PY2 else self.__unicode__()
1302 def __ne__(self, their):
1303 return not(self == their)
1305 def __gt__(self, their): # pragma: no cover
1306 return not(self < their)
1308 def __le__(self, their): # pragma: no cover
1309 return (self == their) or (self < their)
1311 def __ge__(self, their): # pragma: no cover
1312 return (self == their) or (self > their)
1314 def _encode(self): # pragma: no cover
1315 raise NotImplementedError()
1317 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1318 raise NotImplementedError()
1321 """Encode the structure
1323 :returns: DER representation
1325 raw = self._encode()
1326 if self._expl is None:
1328 return b"".join((self._expl, len_encode(len(raw)), raw))
1330 def hexencode(self):
1331 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1333 return hexenc(self.encode())
1343 _ctx_immutable=True,
1347 :param data: either binary or memoryview
1348 :param int offset: initial data's offset
1349 :param bool leavemm: do we need to leave memoryview of remaining
1350 data as is, or convert it to bytes otherwise
1351 :param ctx: optional :ref:`context <ctx>` governing decoding process
1352 :param tag_only: decode only the tag, without length and contents
1353 (used only in Choice and Set structures, trying to
1354 determine if tag satisfies the schema)
1355 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1357 :returns: (Obj, remaining data)
1359 .. seealso:: :ref:`decoding`
1363 elif _ctx_immutable:
1365 tlv = memoryview(data)
1366 if self._expl is None:
1367 result = self._decode(
1370 decode_path=decode_path,
1379 t, tlen, lv = tag_strip(tlv)
1380 except DecodeError as err:
1381 raise err.__class__(
1383 klass=self.__class__,
1384 decode_path=decode_path,
1389 klass=self.__class__,
1390 decode_path=decode_path,
1394 l, llen, v = len_decode(lv)
1395 except LenIndefForm as err:
1396 if not ctx.get("bered", False):
1397 raise err.__class__(
1399 klass=self.__class__,
1400 decode_path=decode_path,
1404 offset += tlen + llen
1405 result = self._decode(
1408 decode_path=decode_path,
1412 if tag_only: # pragma: no cover
1415 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1416 if eoc_expected.tobytes() != EOC:
1419 klass=self.__class__,
1420 decode_path=decode_path,
1424 obj.expl_lenindef = True
1425 except DecodeError as err:
1426 raise err.__class__(
1428 klass=self.__class__,
1429 decode_path=decode_path,
1434 raise NotEnoughData(
1435 "encoded length is longer than data",
1436 klass=self.__class__,
1437 decode_path=decode_path,
1440 result = self._decode(
1442 offset=offset + tlen + llen,
1443 decode_path=decode_path,
1447 if tag_only: # pragma: no cover
1450 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1452 "explicit tag out-of-bound, longer than data",
1453 klass=self.__class__,
1454 decode_path=decode_path,
1457 return obj, (tail if leavemm else tail.tobytes())
1459 def decod(self, data, offset=0, decode_path=(), ctx=None):
1460 """Decode the data, check that tail is empty
1462 :raises ExceedingData: if tail is not empty
1464 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1465 (decode without tail) that also checks that there is no
1468 obj, tail = self.decode(
1471 decode_path=decode_path,
1476 raise ExceedingData(len(tail))
1479 def hexdecode(self, data, *args, **kwargs):
1480 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1482 return self.decode(hexdec(data), *args, **kwargs)
1484 def hexdecod(self, data, *args, **kwargs):
1485 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1487 return self.decod(hexdec(data), *args, **kwargs)
1491 """See :ref:`decoding`
1493 return self._expl is not None
1497 """See :ref:`decoding`
1502 def expl_tlen(self):
1503 """See :ref:`decoding`
1505 return len(self._expl)
1508 def expl_llen(self):
1509 """See :ref:`decoding`
1511 if self.expl_lenindef:
1513 return len(len_encode(self.tlvlen))
1516 def expl_offset(self):
1517 """See :ref:`decoding`
1519 return self.offset - self.expl_tlen - self.expl_llen
1522 def expl_vlen(self):
1523 """See :ref:`decoding`
1528 def expl_tlvlen(self):
1529 """See :ref:`decoding`
1531 return self.expl_tlen + self.expl_llen + self.expl_vlen
1534 def fulloffset(self):
1535 """See :ref:`decoding`
1537 return self.expl_offset if self.expled else self.offset
1541 """See :ref:`decoding`
1543 return self.expl_tlvlen if self.expled else self.tlvlen
1545 def pps_lenindef(self, decode_path):
1546 if self.lenindef and not (
1547 getattr(self, "defined", None) is not None and
1548 self.defined[1].lenindef
1551 asn1_type_name="EOC",
1553 decode_path=decode_path,
1555 self.offset + self.tlvlen -
1556 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1564 if self.expl_lenindef:
1566 asn1_type_name="EOC",
1567 obj_name="EXPLICIT",
1568 decode_path=decode_path,
1569 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1578 class DecodePathDefBy(object):
1579 """DEFINED BY representation inside decode path
1581 __slots__ = ("defined_by",)
1583 def __init__(self, defined_by):
1584 self.defined_by = defined_by
1586 def __ne__(self, their):
1587 return not(self == their)
1589 def __eq__(self, their):
1590 if not isinstance(their, self.__class__):
1592 return self.defined_by == their.defined_by
1595 return "DEFINED BY " + str(self.defined_by)
1598 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1601 ########################################################################
1603 ########################################################################
1605 PP = namedtuple("PP", (
1628 ), **NAMEDTUPLE_KWARGS)
1633 asn1_type_name="unknown",
1650 expl_lenindef=False,
1681 def _colourize(what, colour, with_colours, attrs=("bold",)):
1682 return colored(what, colour, attrs=attrs) if with_colours else what
1685 def colonize_hex(hexed):
1686 """Separate hexadecimal string with colons
1688 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1697 with_decode_path=False,
1698 decode_path_len_decrease=0,
1705 " " if pp.expl_offset is None else
1706 ("-%d" % (pp.offset - pp.expl_offset))
1708 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1710 col = _colourize(col, "red", with_colours, ())
1711 col += _colourize("B", "red", with_colours) if pp.bered else " "
1713 col = "[%d,%d,%4d]%s" % (
1717 LENINDEF_PP_CHAR if pp.lenindef else " "
1719 col = _colourize(col, "green", with_colours, ())
1721 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1722 if decode_path_len > 0:
1723 cols.append(" ." * decode_path_len)
1724 ent = pp.decode_path[-1]
1725 if isinstance(ent, DecodePathDefBy):
1726 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1727 value = str(ent.defined_by)
1730 len(oid_maps) > 0 and
1731 ent.defined_by.asn1_type_name ==
1732 ObjectIdentifier.asn1_type_name
1734 for oid_map in oid_maps:
1735 oid_name = oid_map.get(value)
1736 if oid_name is not None:
1737 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1739 if oid_name is None:
1740 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1742 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1743 if pp.expl is not None:
1744 klass, _, num = pp.expl
1745 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1746 cols.append(_colourize(col, "blue", with_colours))
1747 if pp.impl is not None:
1748 klass, _, num = pp.impl
1749 col = "[%s%d]" % (TagClassReprs[klass], num)
1750 cols.append(_colourize(col, "blue", with_colours))
1751 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1752 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1754 cols.append(_colourize("BER", "red", with_colours))
1755 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1756 if pp.value is not None:
1758 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1760 len(oid_maps) > 0 and
1761 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1763 for oid_map in oid_maps:
1764 oid_name = oid_map.get(value)
1765 if oid_name is not None:
1766 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1768 if pp.asn1_type_name == Integer.asn1_type_name:
1769 hex_repr = hex(int(pp.obj._value))[2:].upper()
1770 if len(hex_repr) % 2 != 0:
1771 hex_repr = "0" + hex_repr
1772 cols.append(_colourize(
1773 "(%s)" % colonize_hex(hex_repr),
1778 if pp.blob.__class__ == binary_type:
1779 cols.append(hexenc(pp.blob))
1780 elif pp.blob.__class__ == tuple:
1781 cols.append(", ".join(pp.blob))
1783 cols.append(_colourize("OPTIONAL", "red", with_colours))
1785 cols.append(_colourize("DEFAULT", "red", with_colours))
1786 if with_decode_path:
1787 cols.append(_colourize(
1788 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1792 return " ".join(cols)
1795 def pp_console_blob(pp, decode_path_len_decrease=0):
1796 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1797 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1798 if decode_path_len > 0:
1799 cols.append(" ." * (decode_path_len + 1))
1800 if pp.blob.__class__ == binary_type:
1801 blob = hexenc(pp.blob).upper()
1802 for i in six_xrange(0, len(blob), 32):
1803 chunk = blob[i:i + 32]
1804 yield " ".join(cols + [colonize_hex(chunk)])
1805 elif pp.blob.__class__ == tuple:
1806 yield " ".join(cols + [", ".join(pp.blob)])
1814 with_decode_path=False,
1815 decode_path_only=(),
1817 """Pretty print object
1819 :param Obj obj: object you want to pretty print
1820 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1821 Its human readable form is printed when OID is met
1822 :param big_blobs: if large binary objects are met (like OctetString
1823 values), do we need to print them too, on separate
1825 :param with_colours: colourize output, if ``termcolor`` library
1827 :param with_decode_path: print decode path
1828 :param decode_path_only: print only that specified decode path
1830 def _pprint_pps(pps):
1832 if hasattr(pp, "_fields"):
1834 decode_path_only != () and
1836 str(p) for p in pp.decode_path[:len(decode_path_only)]
1837 ) != decode_path_only
1841 yield pp_console_row(
1846 with_colours=with_colours,
1847 with_decode_path=with_decode_path,
1848 decode_path_len_decrease=len(decode_path_only),
1850 for row in pp_console_blob(
1852 decode_path_len_decrease=len(decode_path_only),
1856 yield pp_console_row(
1861 with_colours=with_colours,
1862 with_decode_path=with_decode_path,
1863 decode_path_len_decrease=len(decode_path_only),
1866 for row in _pprint_pps(pp):
1868 return "\n".join(_pprint_pps(obj.pps()))
1871 ########################################################################
1872 # ASN.1 primitive types
1873 ########################################################################
1875 BooleanState = namedtuple(
1877 BasicState._fields + ("value",),
1883 """``BOOLEAN`` boolean type
1885 >>> b = Boolean(True)
1887 >>> b == Boolean(True)
1893 tag_default = tag_encode(1)
1894 asn1_type_name = "BOOLEAN"
1906 :param value: set the value. Either boolean type, or
1907 :py:class:`pyderasn.Boolean` object
1908 :param bytes impl: override default tag with ``IMPLICIT`` one
1909 :param bytes expl: override default tag with ``EXPLICIT`` one
1910 :param default: set default value. Type same as in ``value``
1911 :param bool optional: is object ``OPTIONAL`` in sequence
1913 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1914 self._value = None if value is None else self._value_sanitize(value)
1915 if default is not None:
1916 default = self._value_sanitize(default)
1917 self.default = self.__class__(
1923 self._value = default
1925 def _value_sanitize(self, value):
1926 if value.__class__ == bool:
1928 if issubclass(value.__class__, Boolean):
1930 raise InvalidValueType((self.__class__, bool))
1934 return self._value is not None
1936 def __getstate__(self):
1937 return BooleanState(
1952 def __setstate__(self, state):
1953 super(Boolean, self).__setstate__(state)
1954 self._value = state.value
1956 def __nonzero__(self):
1957 self._assert_ready()
1961 self._assert_ready()
1964 def __eq__(self, their):
1965 if their.__class__ == bool:
1966 return self._value == their
1967 if not issubclass(their.__class__, Boolean):
1970 self._value == their._value and
1971 self.tag == their.tag and
1972 self._expl == their._expl
1983 return self.__class__(
1985 impl=self.tag if impl is None else impl,
1986 expl=self._expl if expl is None else expl,
1987 default=self.default if default is None else default,
1988 optional=self.optional if optional is None else optional,
1992 self._assert_ready()
1996 (b"\xFF" if self._value else b"\x00"),
1999 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2001 t, _, lv = tag_strip(tlv)
2002 except DecodeError as err:
2003 raise err.__class__(
2005 klass=self.__class__,
2006 decode_path=decode_path,
2011 klass=self.__class__,
2012 decode_path=decode_path,
2018 l, _, v = len_decode(lv)
2019 except DecodeError as err:
2020 raise err.__class__(
2022 klass=self.__class__,
2023 decode_path=decode_path,
2027 raise InvalidLength(
2028 "Boolean's length must be equal to 1",
2029 klass=self.__class__,
2030 decode_path=decode_path,
2034 raise NotEnoughData(
2035 "encoded length is longer than data",
2036 klass=self.__class__,
2037 decode_path=decode_path,
2040 first_octet = byte2int(v)
2042 if first_octet == 0:
2044 elif first_octet == 0xFF:
2046 elif ctx.get("bered", False):
2051 "unacceptable Boolean value",
2052 klass=self.__class__,
2053 decode_path=decode_path,
2056 obj = self.__class__(
2060 default=self.default,
2061 optional=self.optional,
2062 _decoded=(offset, 1, 1),
2064 obj.ber_encoded = ber_encoded
2068 return pp_console_row(next(self.pps()))
2070 def pps(self, decode_path=()):
2073 asn1_type_name=self.asn1_type_name,
2074 obj_name=self.__class__.__name__,
2075 decode_path=decode_path,
2076 value=str(self._value) if self.ready else None,
2077 optional=self.optional,
2078 default=self == self.default,
2079 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2080 expl=None if self._expl is None else tag_decode(self._expl),
2085 expl_offset=self.expl_offset if self.expled else None,
2086 expl_tlen=self.expl_tlen if self.expled else None,
2087 expl_llen=self.expl_llen if self.expled else None,
2088 expl_vlen=self.expl_vlen if self.expled else None,
2089 expl_lenindef=self.expl_lenindef,
2090 ber_encoded=self.ber_encoded,
2093 for pp in self.pps_lenindef(decode_path):
2097 IntegerState = namedtuple(
2099 BasicState._fields + ("specs", "value", "bound_min", "bound_max"),
2105 """``INTEGER`` integer type
2107 >>> b = Integer(-123)
2109 >>> b == Integer(-123)
2114 >>> Integer(2, bounds=(1, 3))
2116 >>> Integer(5, bounds=(1, 3))
2117 Traceback (most recent call last):
2118 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2122 class Version(Integer):
2129 >>> v = Version("v1")
2136 {'v3': 2, 'v1': 0, 'v2': 1}
2138 __slots__ = ("specs", "_bound_min", "_bound_max")
2139 tag_default = tag_encode(2)
2140 asn1_type_name = "INTEGER"
2154 :param value: set the value. Either integer type, named value
2155 (if ``schema`` is specified in the class), or
2156 :py:class:`pyderasn.Integer` object
2157 :param bounds: set ``(MIN, MAX)`` value constraint.
2158 (-inf, +inf) by default
2159 :param bytes impl: override default tag with ``IMPLICIT`` one
2160 :param bytes expl: override default tag with ``EXPLICIT`` one
2161 :param default: set default value. Type same as in ``value``
2162 :param bool optional: is object ``OPTIONAL`` in sequence
2164 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2166 specs = getattr(self, "schema", {}) if _specs is None else _specs
2167 self.specs = specs if specs.__class__ == dict else dict(specs)
2168 self._bound_min, self._bound_max = getattr(
2171 (float("-inf"), float("+inf")),
2172 ) if bounds is None else bounds
2173 if value is not None:
2174 self._value = self._value_sanitize(value)
2175 if default is not None:
2176 default = self._value_sanitize(default)
2177 self.default = self.__class__(
2183 if self._value is None:
2184 self._value = default
2186 def _value_sanitize(self, value):
2187 if isinstance(value, integer_types):
2189 elif issubclass(value.__class__, Integer):
2190 value = value._value
2191 elif value.__class__ == str:
2192 value = self.specs.get(value)
2194 raise ObjUnknown("integer value: %s" % value)
2196 raise InvalidValueType((self.__class__, int, str))
2197 if not self._bound_min <= value <= self._bound_max:
2198 raise BoundsError(self._bound_min, value, self._bound_max)
2203 return self._value is not None
2205 def __getstate__(self):
2206 return IntegerState(
2224 def __setstate__(self, state):
2225 super(Integer, self).__setstate__(state)
2226 self.specs = state.specs
2227 self._value = state.value
2228 self._bound_min = state.bound_min
2229 self._bound_max = state.bound_max
2232 self._assert_ready()
2233 return int(self._value)
2236 self._assert_ready()
2239 bytes(self._expl or b"") +
2240 str(self._value).encode("ascii"),
2243 def __eq__(self, their):
2244 if isinstance(their, integer_types):
2245 return self._value == their
2246 if not issubclass(their.__class__, Integer):
2249 self._value == their._value and
2250 self.tag == their.tag and
2251 self._expl == their._expl
2254 def __lt__(self, their):
2255 return self._value < their._value
2259 for name, value in iteritems(self.specs):
2260 if value == self._value:
2273 return self.__class__(
2276 (self._bound_min, self._bound_max)
2277 if bounds is None else bounds
2279 impl=self.tag if impl is None else impl,
2280 expl=self._expl if expl is None else expl,
2281 default=self.default if default is None else default,
2282 optional=self.optional if optional is None else optional,
2287 self._assert_ready()
2291 octets = bytearray([0])
2295 octets = bytearray()
2297 octets.append((value & 0xFF) ^ 0xFF)
2299 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2302 octets = bytearray()
2304 octets.append(value & 0xFF)
2306 if octets[-1] & 0x80 > 0:
2309 octets = bytes(octets)
2311 bytes_len = ceil(value.bit_length() / 8) or 1
2314 octets = value.to_bytes(
2319 except OverflowError:
2323 return b"".join((self.tag, len_encode(len(octets)), octets))
2325 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2327 t, _, lv = tag_strip(tlv)
2328 except DecodeError as err:
2329 raise err.__class__(
2331 klass=self.__class__,
2332 decode_path=decode_path,
2337 klass=self.__class__,
2338 decode_path=decode_path,
2344 l, llen, v = len_decode(lv)
2345 except DecodeError as err:
2346 raise err.__class__(
2348 klass=self.__class__,
2349 decode_path=decode_path,
2353 raise NotEnoughData(
2354 "encoded length is longer than data",
2355 klass=self.__class__,
2356 decode_path=decode_path,
2360 raise NotEnoughData(
2362 klass=self.__class__,
2363 decode_path=decode_path,
2366 v, tail = v[:l], v[l:]
2367 first_octet = byte2int(v)
2369 second_octet = byte2int(v[1:])
2371 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2372 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2375 "non normalized integer",
2376 klass=self.__class__,
2377 decode_path=decode_path,
2382 if first_octet & 0x80 > 0:
2383 octets = bytearray()
2384 for octet in bytearray(v):
2385 octets.append(octet ^ 0xFF)
2386 for octet in octets:
2387 value = (value << 8) | octet
2391 for octet in bytearray(v):
2392 value = (value << 8) | octet
2394 value = int.from_bytes(v, byteorder="big", signed=True)
2396 obj = self.__class__(
2398 bounds=(self._bound_min, self._bound_max),
2401 default=self.default,
2402 optional=self.optional,
2404 _decoded=(offset, llen, l),
2406 except BoundsError as err:
2409 klass=self.__class__,
2410 decode_path=decode_path,
2416 return pp_console_row(next(self.pps()))
2418 def pps(self, decode_path=()):
2421 asn1_type_name=self.asn1_type_name,
2422 obj_name=self.__class__.__name__,
2423 decode_path=decode_path,
2424 value=(self.named or str(self._value)) if self.ready else None,
2425 optional=self.optional,
2426 default=self == self.default,
2427 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2428 expl=None if self._expl is None else tag_decode(self._expl),
2433 expl_offset=self.expl_offset if self.expled else None,
2434 expl_tlen=self.expl_tlen if self.expled else None,
2435 expl_llen=self.expl_llen if self.expled else None,
2436 expl_vlen=self.expl_vlen if self.expled else None,
2437 expl_lenindef=self.expl_lenindef,
2440 for pp in self.pps_lenindef(decode_path):
2444 BitStringState = namedtuple(
2446 BasicState._fields + ("specs", "value", "tag_constructed", "defined"),
2451 class BitString(Obj):
2452 """``BIT STRING`` bit string type
2454 >>> BitString(b"hello world")
2455 BIT STRING 88 bits 68656c6c6f20776f726c64
2458 >>> b == b"hello world"
2463 >>> BitString("'0A3B5F291CD'H")
2464 BIT STRING 44 bits 0a3b5f291cd0
2465 >>> b = BitString("'010110000000'B")
2466 BIT STRING 12 bits 5800
2469 >>> b[0], b[1], b[2], b[3]
2470 (False, True, False, True)
2474 [False, True, False, True, True, False, False, False, False, False, False, False]
2478 class KeyUsage(BitString):
2480 ("digitalSignature", 0),
2481 ("nonRepudiation", 1),
2482 ("keyEncipherment", 2),
2485 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2486 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2488 ['nonRepudiation', 'keyEncipherment']
2490 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2494 Pay attention that BIT STRING can be encoded both in primitive
2495 and constructed forms. Decoder always checks constructed form tag
2496 additionally to specified primitive one. If BER decoding is
2497 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2498 of DER restrictions.
2500 __slots__ = ("tag_constructed", "specs", "defined")
2501 tag_default = tag_encode(3)
2502 asn1_type_name = "BIT STRING"
2515 :param value: set the value. Either binary type, tuple of named
2516 values (if ``schema`` is specified in the class),
2517 string in ``'XXX...'B`` form, or
2518 :py:class:`pyderasn.BitString` object
2519 :param bytes impl: override default tag with ``IMPLICIT`` one
2520 :param bytes expl: override default tag with ``EXPLICIT`` one
2521 :param default: set default value. Type same as in ``value``
2522 :param bool optional: is object ``OPTIONAL`` in sequence
2524 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2525 specs = getattr(self, "schema", {}) if _specs is None else _specs
2526 self.specs = specs if specs.__class__ == dict else dict(specs)
2527 self._value = None if value is None else self._value_sanitize(value)
2528 if default is not None:
2529 default = self._value_sanitize(default)
2530 self.default = self.__class__(
2536 self._value = default
2538 tag_klass, _, tag_num = tag_decode(self.tag)
2539 self.tag_constructed = tag_encode(
2541 form=TagFormConstructed,
2545 def _bits2octets(self, bits):
2546 if len(self.specs) > 0:
2547 bits = bits.rstrip("0")
2549 bits += "0" * ((8 - (bit_len % 8)) % 8)
2550 octets = bytearray(len(bits) // 8)
2551 for i in six_xrange(len(octets)):
2552 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2553 return bit_len, bytes(octets)
2555 def _value_sanitize(self, value):
2556 if isinstance(value, (string_types, binary_type)):
2558 isinstance(value, string_types) and
2559 value.startswith("'")
2561 if value.endswith("'B"):
2563 if not frozenset(value) <= SET01:
2564 raise ValueError("B's coding contains unacceptable chars")
2565 return self._bits2octets(value)
2566 if value.endswith("'H"):
2570 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2572 if value.__class__ == binary_type:
2573 return (len(value) * 8, value)
2574 raise InvalidValueType((self.__class__, string_types, binary_type))
2575 if value.__class__ == tuple:
2578 isinstance(value[0], integer_types) and
2579 value[1].__class__ == binary_type
2584 bit = self.specs.get(name)
2586 raise ObjUnknown("BitString value: %s" % name)
2589 return self._bits2octets("")
2590 bits = frozenset(bits)
2591 return self._bits2octets("".join(
2592 ("1" if bit in bits else "0")
2593 for bit in six_xrange(max(bits) + 1)
2595 if issubclass(value.__class__, BitString):
2597 raise InvalidValueType((self.__class__, binary_type, string_types))
2601 return self._value is not None
2603 def __getstate__(self):
2604 return BitStringState(
2618 self.tag_constructed,
2622 def __setstate__(self, state):
2623 super(BitString, self).__setstate__(state)
2624 self.specs = state.specs
2625 self._value = state.value
2626 self.tag_constructed = state.tag_constructed
2627 self.defined = state.defined
2630 self._assert_ready()
2631 for i in six_xrange(self._value[0]):
2636 self._assert_ready()
2637 return self._value[0]
2639 def __bytes__(self):
2640 self._assert_ready()
2641 return self._value[1]
2643 def __eq__(self, their):
2644 if their.__class__ == bytes:
2645 return self._value[1] == their
2646 if not issubclass(their.__class__, BitString):
2649 self._value == their._value and
2650 self.tag == their.tag and
2651 self._expl == their._expl
2656 return [name for name, bit in iteritems(self.specs) if self[bit]]
2666 return self.__class__(
2668 impl=self.tag if impl is None else impl,
2669 expl=self._expl if expl is None else expl,
2670 default=self.default if default is None else default,
2671 optional=self.optional if optional is None else optional,
2675 def __getitem__(self, key):
2676 if key.__class__ == int:
2677 bit_len, octets = self._value
2681 byte2int(memoryview(octets)[key // 8:]) >>
2684 if isinstance(key, string_types):
2685 value = self.specs.get(key)
2687 raise ObjUnknown("BitString value: %s" % key)
2689 raise InvalidValueType((int, str))
2692 self._assert_ready()
2693 bit_len, octets = self._value
2696 len_encode(len(octets) + 1),
2697 int2byte((8 - bit_len % 8) % 8),
2701 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2703 t, tlen, lv = tag_strip(tlv)
2704 except DecodeError as err:
2705 raise err.__class__(
2707 klass=self.__class__,
2708 decode_path=decode_path,
2712 if tag_only: # pragma: no cover
2715 l, llen, v = len_decode(lv)
2716 except DecodeError as err:
2717 raise err.__class__(
2719 klass=self.__class__,
2720 decode_path=decode_path,
2724 raise NotEnoughData(
2725 "encoded length is longer than data",
2726 klass=self.__class__,
2727 decode_path=decode_path,
2731 raise NotEnoughData(
2733 klass=self.__class__,
2734 decode_path=decode_path,
2737 pad_size = byte2int(v)
2738 if l == 1 and pad_size != 0:
2740 "invalid empty value",
2741 klass=self.__class__,
2742 decode_path=decode_path,
2748 klass=self.__class__,
2749 decode_path=decode_path,
2752 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2755 klass=self.__class__,
2756 decode_path=decode_path,
2759 v, tail = v[:l], v[l:]
2760 obj = self.__class__(
2761 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2764 default=self.default,
2765 optional=self.optional,
2767 _decoded=(offset, llen, l),
2770 if t != self.tag_constructed:
2772 klass=self.__class__,
2773 decode_path=decode_path,
2776 if not ctx.get("bered", False):
2778 "unallowed BER constructed encoding",
2779 klass=self.__class__,
2780 decode_path=decode_path,
2783 if tag_only: # pragma: no cover
2787 l, llen, v = len_decode(lv)
2788 except LenIndefForm:
2789 llen, l, v = 1, 0, lv[1:]
2791 except DecodeError as err:
2792 raise err.__class__(
2794 klass=self.__class__,
2795 decode_path=decode_path,
2799 raise NotEnoughData(
2800 "encoded length is longer than data",
2801 klass=self.__class__,
2802 decode_path=decode_path,
2805 if not lenindef and l == 0:
2806 raise NotEnoughData(
2808 klass=self.__class__,
2809 decode_path=decode_path,
2813 sub_offset = offset + tlen + llen
2817 if v[:EOC_LEN].tobytes() == EOC:
2824 "chunk out of bounds",
2825 klass=self.__class__,
2826 decode_path=decode_path + (str(len(chunks) - 1),),
2827 offset=chunks[-1].offset,
2829 sub_decode_path = decode_path + (str(len(chunks)),)
2831 chunk, v_tail = BitString().decode(
2834 decode_path=sub_decode_path,
2837 _ctx_immutable=False,
2841 "expected BitString encoded chunk",
2842 klass=self.__class__,
2843 decode_path=sub_decode_path,
2846 chunks.append(chunk)
2847 sub_offset += chunk.tlvlen
2848 vlen += chunk.tlvlen
2850 if len(chunks) == 0:
2853 klass=self.__class__,
2854 decode_path=decode_path,
2859 for chunk_i, chunk in enumerate(chunks[:-1]):
2860 if chunk.bit_len % 8 != 0:
2862 "BitString chunk is not multiple of 8 bits",
2863 klass=self.__class__,
2864 decode_path=decode_path + (str(chunk_i),),
2865 offset=chunk.offset,
2867 values.append(bytes(chunk))
2868 bit_len += chunk.bit_len
2869 chunk_last = chunks[-1]
2870 values.append(bytes(chunk_last))
2871 bit_len += chunk_last.bit_len
2872 obj = self.__class__(
2873 value=(bit_len, b"".join(values)),
2876 default=self.default,
2877 optional=self.optional,
2879 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2881 obj.lenindef = lenindef
2882 obj.ber_encoded = True
2883 return obj, (v[EOC_LEN:] if lenindef else v)
2886 return pp_console_row(next(self.pps()))
2888 def pps(self, decode_path=()):
2892 bit_len, blob = self._value
2893 value = "%d bits" % bit_len
2894 if len(self.specs) > 0:
2895 blob = tuple(self.named)
2898 asn1_type_name=self.asn1_type_name,
2899 obj_name=self.__class__.__name__,
2900 decode_path=decode_path,
2903 optional=self.optional,
2904 default=self == self.default,
2905 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2906 expl=None if self._expl is None else tag_decode(self._expl),
2911 expl_offset=self.expl_offset if self.expled else None,
2912 expl_tlen=self.expl_tlen if self.expled else None,
2913 expl_llen=self.expl_llen if self.expled else None,
2914 expl_vlen=self.expl_vlen if self.expled else None,
2915 expl_lenindef=self.expl_lenindef,
2916 lenindef=self.lenindef,
2917 ber_encoded=self.ber_encoded,
2920 defined_by, defined = self.defined or (None, None)
2921 if defined_by is not None:
2923 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2925 for pp in self.pps_lenindef(decode_path):
2929 OctetStringState = namedtuple(
2931 BasicState._fields + (
2942 class OctetString(Obj):
2943 """``OCTET STRING`` binary string type
2945 >>> s = OctetString(b"hello world")
2946 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2947 >>> s == OctetString(b"hello world")
2952 >>> OctetString(b"hello", bounds=(4, 4))
2953 Traceback (most recent call last):
2954 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2955 >>> OctetString(b"hell", bounds=(4, 4))
2956 OCTET STRING 4 bytes 68656c6c
2960 Pay attention that OCTET STRING can be encoded both in primitive
2961 and constructed forms. Decoder always checks constructed form tag
2962 additionally to specified primitive one. If BER decoding is
2963 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2964 of DER restrictions.
2966 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2967 tag_default = tag_encode(4)
2968 asn1_type_name = "OCTET STRING"
2982 :param value: set the value. Either binary type, or
2983 :py:class:`pyderasn.OctetString` object
2984 :param bounds: set ``(MIN, MAX)`` value size constraint.
2985 (-inf, +inf) by default
2986 :param bytes impl: override default tag with ``IMPLICIT`` one
2987 :param bytes expl: override default tag with ``EXPLICIT`` one
2988 :param default: set default value. Type same as in ``value``
2989 :param bool optional: is object ``OPTIONAL`` in sequence
2991 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2993 self._bound_min, self._bound_max = getattr(
2997 ) if bounds is None else bounds
2998 if value is not None:
2999 self._value = self._value_sanitize(value)
3000 if default is not None:
3001 default = self._value_sanitize(default)
3002 self.default = self.__class__(
3007 if self._value is None:
3008 self._value = default
3010 tag_klass, _, tag_num = tag_decode(self.tag)
3011 self.tag_constructed = tag_encode(
3013 form=TagFormConstructed,
3017 def _value_sanitize(self, value):
3018 if value.__class__ == binary_type:
3020 elif issubclass(value.__class__, OctetString):
3021 value = value._value
3023 raise InvalidValueType((self.__class__, bytes))
3024 if not self._bound_min <= len(value) <= self._bound_max:
3025 raise BoundsError(self._bound_min, len(value), self._bound_max)
3030 return self._value is not None
3032 def __getstate__(self):
3033 return OctetStringState(
3048 self.tag_constructed,
3052 def __setstate__(self, state):
3053 super(OctetString, self).__setstate__(state)
3054 self._value = state.value
3055 self._bound_min = state.bound_min
3056 self._bound_max = state.bound_max
3057 self.tag_constructed = state.tag_constructed
3058 self.defined = state.defined
3060 def __bytes__(self):
3061 self._assert_ready()
3064 def __eq__(self, their):
3065 if their.__class__ == binary_type:
3066 return self._value == their
3067 if not issubclass(their.__class__, OctetString):
3070 self._value == their._value and
3071 self.tag == their.tag and
3072 self._expl == their._expl
3075 def __lt__(self, their):
3076 return self._value < their._value
3087 return self.__class__(
3090 (self._bound_min, self._bound_max)
3091 if bounds is None else bounds
3093 impl=self.tag if impl is None else impl,
3094 expl=self._expl if expl is None else expl,
3095 default=self.default if default is None else default,
3096 optional=self.optional if optional is None else optional,
3100 self._assert_ready()
3103 len_encode(len(self._value)),
3107 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3109 t, tlen, lv = tag_strip(tlv)
3110 except DecodeError as err:
3111 raise err.__class__(
3113 klass=self.__class__,
3114 decode_path=decode_path,
3121 l, llen, v = len_decode(lv)
3122 except DecodeError as err:
3123 raise err.__class__(
3125 klass=self.__class__,
3126 decode_path=decode_path,
3130 raise NotEnoughData(
3131 "encoded length is longer than data",
3132 klass=self.__class__,
3133 decode_path=decode_path,
3136 v, tail = v[:l], v[l:]
3138 obj = self.__class__(
3140 bounds=(self._bound_min, self._bound_max),
3143 default=self.default,
3144 optional=self.optional,
3145 _decoded=(offset, llen, l),
3148 except DecodeError as err:
3151 klass=self.__class__,
3152 decode_path=decode_path,
3155 except BoundsError as err:
3158 klass=self.__class__,
3159 decode_path=decode_path,
3163 if t != self.tag_constructed:
3165 klass=self.__class__,
3166 decode_path=decode_path,
3169 if not ctx.get("bered", False):
3171 "unallowed BER constructed encoding",
3172 klass=self.__class__,
3173 decode_path=decode_path,
3180 l, llen, v = len_decode(lv)
3181 except LenIndefForm:
3182 llen, l, v = 1, 0, lv[1:]
3184 except DecodeError as err:
3185 raise err.__class__(
3187 klass=self.__class__,
3188 decode_path=decode_path,
3192 raise NotEnoughData(
3193 "encoded length is longer than data",
3194 klass=self.__class__,
3195 decode_path=decode_path,
3199 sub_offset = offset + tlen + llen
3203 if v[:EOC_LEN].tobytes() == EOC:
3210 "chunk out of bounds",
3211 klass=self.__class__,
3212 decode_path=decode_path + (str(len(chunks) - 1),),
3213 offset=chunks[-1].offset,
3215 sub_decode_path = decode_path + (str(len(chunks)),)
3217 chunk, v_tail = OctetString().decode(
3220 decode_path=sub_decode_path,
3223 _ctx_immutable=False,
3227 "expected OctetString encoded chunk",
3228 klass=self.__class__,
3229 decode_path=sub_decode_path,
3232 chunks.append(chunk)
3233 sub_offset += chunk.tlvlen
3234 vlen += chunk.tlvlen
3237 obj = self.__class__(
3238 value=b"".join(bytes(chunk) for chunk in chunks),
3239 bounds=(self._bound_min, self._bound_max),
3242 default=self.default,
3243 optional=self.optional,
3244 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3247 except DecodeError as err:
3250 klass=self.__class__,
3251 decode_path=decode_path,
3254 except BoundsError as err:
3257 klass=self.__class__,
3258 decode_path=decode_path,
3261 obj.lenindef = lenindef
3262 obj.ber_encoded = True
3263 return obj, (v[EOC_LEN:] if lenindef else v)
3266 return pp_console_row(next(self.pps()))
3268 def pps(self, decode_path=()):
3271 asn1_type_name=self.asn1_type_name,
3272 obj_name=self.__class__.__name__,
3273 decode_path=decode_path,
3274 value=("%d bytes" % len(self._value)) if self.ready else None,
3275 blob=self._value if self.ready else None,
3276 optional=self.optional,
3277 default=self == self.default,
3278 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3279 expl=None if self._expl is None else tag_decode(self._expl),
3284 expl_offset=self.expl_offset if self.expled else None,
3285 expl_tlen=self.expl_tlen if self.expled else None,
3286 expl_llen=self.expl_llen if self.expled else None,
3287 expl_vlen=self.expl_vlen if self.expled else None,
3288 expl_lenindef=self.expl_lenindef,
3289 lenindef=self.lenindef,
3290 ber_encoded=self.ber_encoded,
3293 defined_by, defined = self.defined or (None, None)
3294 if defined_by is not None:
3296 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3298 for pp in self.pps_lenindef(decode_path):
3302 NullState = namedtuple("NullState", BasicState._fields, **NAMEDTUPLE_KWARGS)
3306 """``NULL`` null object
3314 tag_default = tag_encode(5)
3315 asn1_type_name = "NULL"
3319 value=None, # unused, but Sequence passes it
3326 :param bytes impl: override default tag with ``IMPLICIT`` one
3327 :param bytes expl: override default tag with ``EXPLICIT`` one
3328 :param bool optional: is object ``OPTIONAL`` in sequence
3330 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3337 def __getstate__(self):
3352 def __eq__(self, their):
3353 if not issubclass(their.__class__, Null):
3356 self.tag == their.tag and
3357 self._expl == their._expl
3367 return self.__class__(
3368 impl=self.tag if impl is None else impl,
3369 expl=self._expl if expl is None else expl,
3370 optional=self.optional if optional is None else optional,
3374 return self.tag + len_encode(0)
3376 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3378 t, _, lv = tag_strip(tlv)
3379 except DecodeError as err:
3380 raise err.__class__(
3382 klass=self.__class__,
3383 decode_path=decode_path,
3388 klass=self.__class__,
3389 decode_path=decode_path,
3392 if tag_only: # pragma: no cover
3395 l, _, v = len_decode(lv)
3396 except DecodeError as err:
3397 raise err.__class__(
3399 klass=self.__class__,
3400 decode_path=decode_path,
3404 raise InvalidLength(
3405 "Null must have zero length",
3406 klass=self.__class__,
3407 decode_path=decode_path,
3410 obj = self.__class__(
3413 optional=self.optional,
3414 _decoded=(offset, 1, 0),
3419 return pp_console_row(next(self.pps()))
3421 def pps(self, decode_path=()):
3424 asn1_type_name=self.asn1_type_name,
3425 obj_name=self.__class__.__name__,
3426 decode_path=decode_path,
3427 optional=self.optional,
3428 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3429 expl=None if self._expl is None else tag_decode(self._expl),
3434 expl_offset=self.expl_offset if self.expled else None,
3435 expl_tlen=self.expl_tlen if self.expled else None,
3436 expl_llen=self.expl_llen if self.expled else None,
3437 expl_vlen=self.expl_vlen if self.expled else None,
3438 expl_lenindef=self.expl_lenindef,
3441 for pp in self.pps_lenindef(decode_path):
3445 ObjectIdentifierState = namedtuple(
3446 "ObjectIdentifierState",
3447 BasicState._fields + ("value", "defines"),
3452 class ObjectIdentifier(Obj):
3453 """``OBJECT IDENTIFIER`` OID type
3455 >>> oid = ObjectIdentifier((1, 2, 3))
3456 OBJECT IDENTIFIER 1.2.3
3457 >>> oid == ObjectIdentifier("1.2.3")
3463 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3464 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3466 >>> str(ObjectIdentifier((3, 1)))
3467 Traceback (most recent call last):
3468 pyderasn.InvalidOID: unacceptable first arc value
3470 __slots__ = ("defines",)
3471 tag_default = tag_encode(6)
3472 asn1_type_name = "OBJECT IDENTIFIER"
3485 :param value: set the value. Either tuples of integers,
3486 string of "."-concatenated integers, or
3487 :py:class:`pyderasn.ObjectIdentifier` object
3488 :param defines: sequence of tuples. Each tuple has two elements.
3489 First one is relative to current one decode
3490 path, aiming to the field defined by that OID.
3491 Read about relative path in
3492 :py:func:`pyderasn.abs_decode_path`. Second
3493 tuple element is ``{OID: pyderasn.Obj()}``
3494 dictionary, mapping between current OID value
3495 and structure applied to defined field.
3496 :ref:`Read about DEFINED BY <definedby>`
3497 :param bytes impl: override default tag with ``IMPLICIT`` one
3498 :param bytes expl: override default tag with ``EXPLICIT`` one
3499 :param default: set default value. Type same as in ``value``
3500 :param bool optional: is object ``OPTIONAL`` in sequence
3502 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3504 if value is not None:
3505 self._value = self._value_sanitize(value)
3506 if default is not None:
3507 default = self._value_sanitize(default)
3508 self.default = self.__class__(
3513 if self._value is None:
3514 self._value = default
3515 self.defines = defines
3517 def __add__(self, their):
3518 if their.__class__ == tuple:
3519 return self.__class__(self._value + their)
3520 if isinstance(their, self.__class__):
3521 return self.__class__(self._value + their._value)
3522 raise InvalidValueType((self.__class__, tuple))
3524 def _value_sanitize(self, value):
3525 if issubclass(value.__class__, ObjectIdentifier):
3527 if isinstance(value, string_types):
3529 value = tuple(pureint(arc) for arc in value.split("."))
3531 raise InvalidOID("unacceptable arcs values")
3532 if value.__class__ == tuple:
3534 raise InvalidOID("less than 2 arcs")
3535 first_arc = value[0]
3536 if first_arc in (0, 1):
3537 if not (0 <= value[1] <= 39):
3538 raise InvalidOID("second arc is too wide")
3539 elif first_arc == 2:
3542 raise InvalidOID("unacceptable first arc value")
3543 if not all(arc >= 0 for arc in value):
3544 raise InvalidOID("negative arc value")
3546 raise InvalidValueType((self.__class__, str, tuple))
3550 return self._value is not None
3552 def __getstate__(self):
3553 return ObjectIdentifierState(
3569 def __setstate__(self, state):
3570 super(ObjectIdentifier, self).__setstate__(state)
3571 self._value = state.value
3572 self.defines = state.defines
3575 self._assert_ready()
3576 return iter(self._value)
3579 return ".".join(str(arc) for arc in self._value or ())
3582 self._assert_ready()
3585 bytes(self._expl or b"") +
3586 str(self._value).encode("ascii"),
3589 def __eq__(self, their):
3590 if their.__class__ == tuple:
3591 return self._value == their
3592 if not issubclass(their.__class__, ObjectIdentifier):
3595 self.tag == their.tag and
3596 self._expl == their._expl and
3597 self._value == their._value
3600 def __lt__(self, their):
3601 return self._value < their._value
3612 return self.__class__(
3614 defines=self.defines if defines is None else defines,
3615 impl=self.tag if impl is None else impl,
3616 expl=self._expl if expl is None else expl,
3617 default=self.default if default is None else default,
3618 optional=self.optional if optional is None else optional,
3622 self._assert_ready()
3624 first_value = value[1]
3625 first_arc = value[0]
3628 elif first_arc == 1:
3630 elif first_arc == 2:
3632 else: # pragma: no cover
3633 raise RuntimeError("invalid arc is stored")
3634 octets = [zero_ended_encode(first_value)]
3635 for arc in value[2:]:
3636 octets.append(zero_ended_encode(arc))
3637 v = b"".join(octets)
3638 return b"".join((self.tag, len_encode(len(v)), v))
3640 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3642 t, _, lv = tag_strip(tlv)
3643 except DecodeError as err:
3644 raise err.__class__(
3646 klass=self.__class__,
3647 decode_path=decode_path,
3652 klass=self.__class__,
3653 decode_path=decode_path,
3656 if tag_only: # pragma: no cover
3659 l, llen, v = len_decode(lv)
3660 except DecodeError as err:
3661 raise err.__class__(
3663 klass=self.__class__,
3664 decode_path=decode_path,
3668 raise NotEnoughData(
3669 "encoded length is longer than data",
3670 klass=self.__class__,
3671 decode_path=decode_path,
3675 raise NotEnoughData(
3677 klass=self.__class__,
3678 decode_path=decode_path,
3681 v, tail = v[:l], v[l:]
3688 octet = indexbytes(v, i)
3689 if i == 0 and octet == 0x80:
3690 if ctx.get("bered", False):
3693 raise DecodeError("non normalized arc encoding")
3694 arc = (arc << 7) | (octet & 0x7F)
3695 if octet & 0x80 == 0:
3703 klass=self.__class__,
3704 decode_path=decode_path,
3708 second_arc = arcs[0]
3709 if 0 <= second_arc <= 39:
3711 elif 40 <= second_arc <= 79:
3717 obj = self.__class__(
3718 value=tuple([first_arc, second_arc] + arcs[1:]),
3721 default=self.default,
3722 optional=self.optional,
3723 _decoded=(offset, llen, l),
3726 obj.ber_encoded = True
3730 return pp_console_row(next(self.pps()))
3732 def pps(self, decode_path=()):
3735 asn1_type_name=self.asn1_type_name,
3736 obj_name=self.__class__.__name__,
3737 decode_path=decode_path,
3738 value=str(self) if self.ready else None,
3739 optional=self.optional,
3740 default=self == self.default,
3741 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3742 expl=None if self._expl is None else tag_decode(self._expl),
3747 expl_offset=self.expl_offset if self.expled else None,
3748 expl_tlen=self.expl_tlen if self.expled else None,
3749 expl_llen=self.expl_llen if self.expled else None,
3750 expl_vlen=self.expl_vlen if self.expled else None,
3751 expl_lenindef=self.expl_lenindef,
3752 ber_encoded=self.ber_encoded,
3755 for pp in self.pps_lenindef(decode_path):
3759 class Enumerated(Integer):
3760 """``ENUMERATED`` integer type
3762 This type is identical to :py:class:`pyderasn.Integer`, but requires
3763 schema to be specified and does not accept values missing from it.
3766 tag_default = tag_encode(10)
3767 asn1_type_name = "ENUMERATED"
3778 bounds=None, # dummy argument, workability for Integer.decode
3780 super(Enumerated, self).__init__(
3781 value, bounds, impl, expl, default, optional, _specs, _decoded,
3783 if len(self.specs) == 0:
3784 raise ValueError("schema must be specified")
3786 def _value_sanitize(self, value):
3787 if isinstance(value, self.__class__):
3788 value = value._value
3789 elif isinstance(value, integer_types):
3790 for _value in itervalues(self.specs):
3795 "unknown integer value: %s" % value,
3796 klass=self.__class__,
3798 elif isinstance(value, string_types):
3799 value = self.specs.get(value)
3801 raise ObjUnknown("integer value: %s" % value)
3803 raise InvalidValueType((self.__class__, int, str))
3815 return self.__class__(
3817 impl=self.tag if impl is None else impl,
3818 expl=self._expl if expl is None else expl,
3819 default=self.default if default is None else default,
3820 optional=self.optional if optional is None else optional,
3825 def escape_control_unicode(c):
3826 if unicat(c)[0] == "C":
3827 c = repr(c).lstrip("u").strip("'")
3831 class CommonString(OctetString):
3832 """Common class for all strings
3834 Everything resembles :py:class:`pyderasn.OctetString`, except
3835 ability to deal with unicode text strings.
3837 >>> hexenc("привет мир".encode("utf-8"))
3838 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3839 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3841 >>> s = UTF8String("привет мир")
3842 UTF8String UTF8String привет мир
3844 'привет мир'
3845 >>> hexenc(bytes(s))
3846 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3848 >>> PrintableString("привет мир")
3849 Traceback (most recent call last):
3850 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3852 >>> BMPString("ада", bounds=(2, 2))
3853 Traceback (most recent call last):
3854 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3855 >>> s = BMPString("ад", bounds=(2, 2))
3858 >>> hexenc(bytes(s))
3866 * - :py:class:`pyderasn.UTF8String`
3868 * - :py:class:`pyderasn.NumericString`
3870 * - :py:class:`pyderasn.PrintableString`
3872 * - :py:class:`pyderasn.TeletexString`
3874 * - :py:class:`pyderasn.T61String`
3876 * - :py:class:`pyderasn.VideotexString`
3878 * - :py:class:`pyderasn.IA5String`
3880 * - :py:class:`pyderasn.GraphicString`
3882 * - :py:class:`pyderasn.VisibleString`
3884 * - :py:class:`pyderasn.ISO646String`
3886 * - :py:class:`pyderasn.GeneralString`
3888 * - :py:class:`pyderasn.UniversalString`
3890 * - :py:class:`pyderasn.BMPString`
3895 def _value_sanitize(self, value):
3897 value_decoded = None
3898 if isinstance(value, self.__class__):
3899 value_raw = value._value
3900 elif value.__class__ == text_type:
3901 value_decoded = value
3902 elif value.__class__ == binary_type:
3905 raise InvalidValueType((self.__class__, text_type, binary_type))
3908 value_decoded.encode(self.encoding)
3909 if value_raw is None else value_raw
3912 value_raw.decode(self.encoding)
3913 if value_decoded is None else value_decoded
3915 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3916 raise DecodeError(str(err))
3917 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3925 def __eq__(self, their):
3926 if their.__class__ == binary_type:
3927 return self._value == their
3928 if their.__class__ == text_type:
3929 return self._value == their.encode(self.encoding)
3930 if not isinstance(their, self.__class__):
3933 self._value == their._value and
3934 self.tag == their.tag and
3935 self._expl == their._expl
3938 def __unicode__(self):
3940 return self._value.decode(self.encoding)
3941 return text_type(self._value)
3944 return pp_console_row(next(self.pps(no_unicode=PY2)))
3946 def pps(self, decode_path=(), no_unicode=False):
3950 hexenc(bytes(self)) if no_unicode else
3951 "".join(escape_control_unicode(c) for c in self.__unicode__())
3955 asn1_type_name=self.asn1_type_name,
3956 obj_name=self.__class__.__name__,
3957 decode_path=decode_path,
3959 optional=self.optional,
3960 default=self == self.default,
3961 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3962 expl=None if self._expl is None else tag_decode(self._expl),
3967 expl_offset=self.expl_offset if self.expled else None,
3968 expl_tlen=self.expl_tlen if self.expled else None,
3969 expl_llen=self.expl_llen if self.expled else None,
3970 expl_vlen=self.expl_vlen if self.expled else None,
3971 expl_lenindef=self.expl_lenindef,
3972 ber_encoded=self.ber_encoded,
3975 for pp in self.pps_lenindef(decode_path):
3979 class UTF8String(CommonString):
3981 tag_default = tag_encode(12)
3983 asn1_type_name = "UTF8String"
3986 class AllowableCharsMixin(object):
3988 def allowable_chars(self):
3990 return self._allowable_chars
3991 return frozenset(six_unichr(c) for c in self._allowable_chars)
3994 class NumericString(AllowableCharsMixin, CommonString):
3997 Its value is properly sanitized: only ASCII digits with spaces can
4000 >>> NumericString().allowable_chars
4001 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
4004 tag_default = tag_encode(18)
4006 asn1_type_name = "NumericString"
4007 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
4009 def _value_sanitize(self, value):
4010 value = super(NumericString, self)._value_sanitize(value)
4011 if not frozenset(value) <= self._allowable_chars:
4012 raise DecodeError("non-numeric value")
4016 PrintableStringState = namedtuple(
4017 "PrintableStringState",
4018 OctetStringState._fields + ("allowable_chars",),
4023 class PrintableString(AllowableCharsMixin, CommonString):
4026 Its value is properly sanitized: see X.680 41.4 table 10.
4028 >>> PrintableString().allowable_chars
4029 frozenset([' ', "'", ..., 'z'])
4030 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4031 PrintableString PrintableString foo*bar
4032 >>> obj.allow_asterisk, obj.allow_ampersand
4036 tag_default = tag_encode(19)
4038 asn1_type_name = "PrintableString"
4039 _allowable_chars = frozenset(
4040 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4042 _asterisk = frozenset("*".encode("ascii"))
4043 _ampersand = frozenset("&".encode("ascii"))
4055 allow_asterisk=False,
4056 allow_ampersand=False,
4059 :param allow_asterisk: allow asterisk character
4060 :param allow_ampersand: allow ampersand character
4063 self._allowable_chars |= self._asterisk
4065 self._allowable_chars |= self._ampersand
4066 super(PrintableString, self).__init__(
4067 value, bounds, impl, expl, default, optional, _decoded, ctx,
4071 def allow_asterisk(self):
4072 """Is asterisk character allowed?
4074 return self._asterisk <= self._allowable_chars
4077 def allow_ampersand(self):
4078 """Is ampersand character allowed?
4080 return self._ampersand <= self._allowable_chars
4082 def _value_sanitize(self, value):
4083 value = super(PrintableString, self)._value_sanitize(value)
4084 if not frozenset(value) <= self._allowable_chars:
4085 raise DecodeError("non-printable value")
4088 def __getstate__(self):
4089 return PrintableStringState(
4090 *super(PrintableString, self).__getstate__(),
4091 **{"allowable_chars": self._allowable_chars}
4094 def __setstate__(self, state):
4095 super(PrintableString, self).__setstate__(state)
4096 self._allowable_chars = state.allowable_chars
4107 return self.__class__(
4110 (self._bound_min, self._bound_max)
4111 if bounds is None else bounds
4113 impl=self.tag if impl is None else impl,
4114 expl=self._expl if expl is None else expl,
4115 default=self.default if default is None else default,
4116 optional=self.optional if optional is None else optional,
4117 allow_asterisk=self.allow_asterisk,
4118 allow_ampersand=self.allow_ampersand,
4122 class TeletexString(CommonString):
4124 tag_default = tag_encode(20)
4126 asn1_type_name = "TeletexString"
4129 class T61String(TeletexString):
4131 asn1_type_name = "T61String"
4134 class VideotexString(CommonString):
4136 tag_default = tag_encode(21)
4137 encoding = "iso-8859-1"
4138 asn1_type_name = "VideotexString"
4141 class IA5String(CommonString):
4143 tag_default = tag_encode(22)
4145 asn1_type_name = "IA5"
4148 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4149 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4150 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4153 class VisibleString(CommonString):
4155 tag_default = tag_encode(26)
4157 asn1_type_name = "VisibleString"
4160 UTCTimeState = namedtuple(
4162 OctetStringState._fields + ("ber_raw",),
4167 def str_to_time_fractions(value):
4169 year, v = (v // 10**10), (v % 10**10)
4170 month, v = (v // 10**8), (v % 10**8)
4171 day, v = (v // 10**6), (v % 10**6)
4172 hour, v = (v // 10**4), (v % 10**4)
4173 minute, second = (v // 100), (v % 100)
4174 return year, month, day, hour, minute, second
4177 class UTCTime(VisibleString):
4178 """``UTCTime`` datetime type
4180 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4181 UTCTime UTCTime 2017-09-30T22:07:50
4187 datetime.datetime(2017, 9, 30, 22, 7, 50)
4188 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4189 datetime.datetime(1957, 9, 30, 22, 7, 50)
4191 If BER encoded value was met, then ``ber_raw`` attribute will hold
4192 its raw representation.
4196 Pay attention that UTCTime can not hold full year, so all years
4197 having < 50 years are treated as 20xx, 19xx otherwise, according
4198 to X.509 recommendation.
4202 No strict validation of UTC offsets are made, but very crude:
4204 * minutes are not exceeding 60
4205 * offset value is not exceeding 14 hours
4207 __slots__ = ("ber_raw",)
4208 tag_default = tag_encode(23)
4210 asn1_type_name = "UTCTime"
4220 bounds=None, # dummy argument, workability for OctetString.decode
4224 :param value: set the value. Either datetime type, or
4225 :py:class:`pyderasn.UTCTime` object
4226 :param bytes impl: override default tag with ``IMPLICIT`` one
4227 :param bytes expl: override default tag with ``EXPLICIT`` one
4228 :param default: set default value. Type same as in ``value``
4229 :param bool optional: is object ``OPTIONAL`` in sequence
4231 super(UTCTime, self).__init__(
4232 None, None, impl, expl, None, optional, _decoded, ctx,
4236 if value is not None:
4237 self._value, self.ber_raw = self._value_sanitize(value, ctx)
4238 self.ber_encoded = self.ber_raw is not None
4239 if default is not None:
4240 default, _ = self._value_sanitize(default)
4241 self.default = self.__class__(
4246 if self._value is None:
4247 self._value = default
4249 self.optional = optional
4251 def _strptime_bered(self, value):
4252 year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
4255 raise ValueError("no timezone")
4256 year += 2000 if year < 50 else 1900
4257 decoded = datetime(year, month, day, hour, minute)
4259 if value[-1] == "Z":
4263 raise ValueError("invalid UTC offset")
4264 if value[-5] == "-":
4266 elif value[-5] == "+":
4269 raise ValueError("invalid UTC offset")
4270 v = pureint(value[-4:])
4271 offset, v = (60 * (v % 100)), v // 100
4273 raise ValueError("invalid UTC offset minutes")
4275 if offset > 14 * 3600:
4276 raise ValueError("too big UTC offset")
4280 return offset, decoded
4282 raise ValueError("invalid UTC offset seconds")
4283 seconds = pureint(value)
4285 raise ValueError("invalid seconds value")
4286 return offset, decoded + timedelta(seconds=seconds)
4288 def _strptime(self, value):
4289 # datetime.strptime's format: %y%m%d%H%M%SZ
4290 if len(value) != LEN_YYMMDDHHMMSSZ:
4291 raise ValueError("invalid UTCTime length")
4292 if value[-1] != "Z":
4293 raise ValueError("non UTC timezone")
4294 year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
4295 year += 2000 if year < 50 else 1900
4296 return datetime(year, month, day, hour, minute, second)
4298 def _dt_sanitize(self, value):
4299 if value.year < 1950 or value.year > 2049:
4300 raise ValueError("UTCTime can hold only 1950-2049 years")
4301 return value.replace(microsecond=0)
4303 def _value_sanitize(self, value, ctx=None):
4304 if value.__class__ == binary_type:
4306 value_decoded = value.decode("ascii")
4307 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4308 raise DecodeError("invalid UTCTime encoding: %r" % err)
4311 return self._strptime(value_decoded), None
4312 except (TypeError, ValueError) as _err:
4314 if (ctx is not None) and ctx.get("bered", False):
4316 offset, _value = self._strptime_bered(value_decoded)
4317 _value = _value - timedelta(seconds=offset)
4318 return self._dt_sanitize(_value), value
4319 except (TypeError, ValueError, OverflowError) as _err:
4322 "invalid %s format: %r" % (self.asn1_type_name, err),
4323 klass=self.__class__,
4325 if isinstance(value, self.__class__):
4326 return value._value, None
4327 if value.__class__ == datetime:
4328 return self._dt_sanitize(value), None
4329 raise InvalidValueType((self.__class__, datetime))
4331 def _pp_value(self):
4333 value = self._value.isoformat()
4334 if self.ber_encoded:
4335 value += " (%s)" % self.ber_raw
4338 def __unicode__(self):
4340 value = self._value.isoformat()
4341 if self.ber_encoded:
4342 value += " (%s)" % self.ber_raw
4344 return text_type(self._pp_value())
4346 def __getstate__(self):
4347 return UTCTimeState(
4348 *super(UTCTime, self).__getstate__(),
4349 **{"ber_raw": self.ber_raw}
4352 def __setstate__(self, state):
4353 super(UTCTime, self).__setstate__(state)
4354 self.ber_raw = state.ber_raw
4356 def __bytes__(self):
4357 self._assert_ready()
4358 return self._encode_time()
4360 def __eq__(self, their):
4361 if their.__class__ == binary_type:
4362 return self._encode_time() == their
4363 if their.__class__ == datetime:
4364 return self.todatetime() == their
4365 if not isinstance(their, self.__class__):
4368 self._value == their._value and
4369 self.tag == their.tag and
4370 self._expl == their._expl
4373 def _encode_time(self):
4374 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4377 self._assert_ready()
4378 value = self._encode_time()
4379 return b"".join((self.tag, len_encode(len(value)), value))
4381 def todatetime(self):
4385 return pp_console_row(next(self.pps()))
4387 def pps(self, decode_path=()):
4390 asn1_type_name=self.asn1_type_name,
4391 obj_name=self.__class__.__name__,
4392 decode_path=decode_path,
4393 value=self._pp_value(),
4394 optional=self.optional,
4395 default=self == self.default,
4396 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4397 expl=None if self._expl is None else tag_decode(self._expl),
4402 expl_offset=self.expl_offset if self.expled else None,
4403 expl_tlen=self.expl_tlen if self.expled else None,
4404 expl_llen=self.expl_llen if self.expled else None,
4405 expl_vlen=self.expl_vlen if self.expled else None,
4406 expl_lenindef=self.expl_lenindef,
4407 ber_encoded=self.ber_encoded,
4410 for pp in self.pps_lenindef(decode_path):
4414 class GeneralizedTime(UTCTime):
4415 """``GeneralizedTime`` datetime type
4417 This type is similar to :py:class:`pyderasn.UTCTime`.
4419 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4420 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4422 '20170930220750.000123Z'
4423 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4424 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4428 Only microsecond fractions are supported in DER encoding.
4429 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4430 higher precision values.
4434 BER encoded data can loss information (accuracy) during decoding
4435 because of float transformations.
4439 Local times (without explicit timezone specification) are treated
4440 as UTC one, no transformations are made.
4444 Zero year is unsupported.
4447 tag_default = tag_encode(24)
4448 asn1_type_name = "GeneralizedTime"
4450 def _dt_sanitize(self, value):
4453 def _strptime_bered(self, value):
4454 if len(value) < 4 + 3 * 2:
4455 raise ValueError("invalid GeneralizedTime")
4456 year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
4457 decoded = datetime(year, month, day, hour)
4458 offset, value = 0, value[10:]
4460 return offset, decoded
4461 if value[-1] == "Z":
4464 for char, sign in (("-", -1), ("+", 1)):
4465 idx = value.rfind(char)
4468 offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
4469 v = pureint(offset_raw)
4470 if len(offset_raw) == 4:
4471 offset, v = (60 * (v % 100)), v // 100
4473 raise ValueError("invalid UTC offset minutes")
4474 elif len(offset_raw) == 2:
4477 raise ValueError("invalid UTC offset")
4479 if offset > 14 * 3600:
4480 raise ValueError("too big UTC offset")
4484 return offset, decoded
4485 if value[0] in DECIMAL_SIGNS:
4487 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4490 raise ValueError("stripped minutes")
4491 decoded += timedelta(seconds=60 * pureint(value[:2]))
4494 return offset, decoded
4495 if value[0] in DECIMAL_SIGNS:
4497 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4500 raise ValueError("stripped seconds")
4501 decoded += timedelta(seconds=pureint(value[:2]))
4504 return offset, decoded
4505 if value[0] not in DECIMAL_SIGNS:
4506 raise ValueError("invalid format after seconds")
4508 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4511 def _strptime(self, value):
4513 if l == LEN_YYYYMMDDHHMMSSZ:
4514 # datetime.strptime's format: %Y%m%d%H%M%SZ
4515 if value[-1] != "Z":
4516 raise ValueError("non UTC timezone")
4517 return datetime(*str_to_time_fractions(value[:-1]))
4518 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4519 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4520 if value[-1] != "Z":
4521 raise ValueError("non UTC timezone")
4522 if value[14] != ".":
4523 raise ValueError("no fractions separator")
4526 raise ValueError("trailing zero")
4529 raise ValueError("only microsecond fractions are supported")
4530 us = pureint(us + ("0" * (6 - us_len)))
4531 year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
4532 return datetime(year, month, day, hour, minute, second, us)
4533 raise ValueError("invalid GeneralizedTime length")
4535 def _encode_time(self):
4537 encoded = value.strftime("%Y%m%d%H%M%S")
4538 if value.microsecond > 0:
4539 encoded += (".%06d" % value.microsecond).rstrip("0")
4540 return (encoded + "Z").encode("ascii")
4543 class GraphicString(CommonString):
4545 tag_default = tag_encode(25)
4546 encoding = "iso-8859-1"
4547 asn1_type_name = "GraphicString"
4550 class ISO646String(VisibleString):
4552 asn1_type_name = "ISO646String"
4555 class GeneralString(CommonString):
4557 tag_default = tag_encode(27)
4558 encoding = "iso-8859-1"
4559 asn1_type_name = "GeneralString"
4562 class UniversalString(CommonString):
4564 tag_default = tag_encode(28)
4565 encoding = "utf-32-be"
4566 asn1_type_name = "UniversalString"
4569 class BMPString(CommonString):
4571 tag_default = tag_encode(30)
4572 encoding = "utf-16-be"
4573 asn1_type_name = "BMPString"
4576 ChoiceState = namedtuple(
4578 BasicState._fields + ("specs", "value",),
4584 """``CHOICE`` special type
4588 class GeneralName(Choice):
4590 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4591 ("dNSName", IA5String(impl=tag_ctxp(2))),
4594 >>> gn = GeneralName()
4596 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4597 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4598 >>> gn["dNSName"] = IA5String("bar.baz")
4599 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4600 >>> gn["rfc822Name"]
4603 [2] IA5String IA5 bar.baz
4606 >>> gn.value == gn["dNSName"]
4609 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4611 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4612 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4614 __slots__ = ("specs",)
4616 asn1_type_name = "CHOICE"
4629 :param value: set the value. Either ``(choice, value)`` tuple, or
4630 :py:class:`pyderasn.Choice` object
4631 :param bytes impl: can not be set, do **not** use it
4632 :param bytes expl: override default tag with ``EXPLICIT`` one
4633 :param default: set default value. Type same as in ``value``
4634 :param bool optional: is object ``OPTIONAL`` in sequence
4636 if impl is not None:
4637 raise ValueError("no implicit tag allowed for CHOICE")
4638 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4640 schema = getattr(self, "schema", ())
4641 if len(schema) == 0:
4642 raise ValueError("schema must be specified")
4644 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
4647 if value is not None:
4648 self._value = self._value_sanitize(value)
4649 if default is not None:
4650 default_value = self._value_sanitize(default)
4651 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4652 default_obj.specs = self.specs
4653 default_obj._value = default_value
4654 self.default = default_obj
4656 self._value = copy(default_obj._value)
4658 def _value_sanitize(self, value):
4659 if (value.__class__ == tuple) and len(value) == 2:
4661 spec = self.specs.get(choice)
4663 raise ObjUnknown(choice)
4664 if not isinstance(obj, spec.__class__):
4665 raise InvalidValueType((spec,))
4666 return (choice, spec(obj))
4667 if isinstance(value, self.__class__):
4669 raise InvalidValueType((self.__class__, tuple))
4673 return self._value is not None and self._value[1].ready
4677 return self.expl_lenindef or (
4678 (self._value is not None) and
4679 self._value[1].bered
4682 def __getstate__(self):
4699 def __setstate__(self, state):
4700 super(Choice, self).__setstate__(state)
4701 self.specs = state.specs
4702 self._value = state.value
4704 def __eq__(self, their):
4705 if (their.__class__ == tuple) and len(their) == 2:
4706 return self._value == their
4707 if not isinstance(their, self.__class__):
4710 self.specs == their.specs and
4711 self._value == their._value
4721 return self.__class__(
4724 expl=self._expl if expl is None else expl,
4725 default=self.default if default is None else default,
4726 optional=self.optional if optional is None else optional,
4731 self._assert_ready()
4732 return self._value[0]
4736 self._assert_ready()
4737 return self._value[1]
4739 def __getitem__(self, key):
4740 if key not in self.specs:
4741 raise ObjUnknown(key)
4742 if self._value is None:
4744 choice, value = self._value
4749 def __setitem__(self, key, value):
4750 spec = self.specs.get(key)
4752 raise ObjUnknown(key)
4753 if not isinstance(value, spec.__class__):
4754 raise InvalidValueType((spec.__class__,))
4755 self._value = (key, spec(value))
4763 return self._value[1].decoded if self.ready else False
4766 self._assert_ready()
4767 return self._value[1].encode()
4769 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4770 for choice, spec in iteritems(self.specs):
4771 sub_decode_path = decode_path + (choice,)
4777 decode_path=sub_decode_path,
4780 _ctx_immutable=False,
4787 klass=self.__class__,
4788 decode_path=decode_path,
4791 if tag_only: # pragma: no cover
4793 value, tail = spec.decode(
4797 decode_path=sub_decode_path,
4799 _ctx_immutable=False,
4801 obj = self.__class__(
4804 default=self.default,
4805 optional=self.optional,
4806 _decoded=(offset, 0, value.fulllen),
4808 obj._value = (choice, value)
4812 value = pp_console_row(next(self.pps()))
4814 value = "%s[%r]" % (value, self.value)
4817 def pps(self, decode_path=()):
4820 asn1_type_name=self.asn1_type_name,
4821 obj_name=self.__class__.__name__,
4822 decode_path=decode_path,
4823 value=self.choice if self.ready else None,
4824 optional=self.optional,
4825 default=self == self.default,
4826 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4827 expl=None if self._expl is None else tag_decode(self._expl),
4832 expl_lenindef=self.expl_lenindef,
4836 yield self.value.pps(decode_path=decode_path + (self.choice,))
4837 for pp in self.pps_lenindef(decode_path):
4841 class PrimitiveTypes(Choice):
4842 """Predefined ``CHOICE`` for all generic primitive types
4844 It could be useful for general decoding of some unspecified values:
4846 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4847 OCTET STRING 3 bytes 666f6f
4848 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4852 schema = tuple((klass.__name__, klass()) for klass in (
4876 AnyState = namedtuple(
4878 BasicState._fields + ("value", "defined"),
4884 """``ANY`` special type
4886 >>> Any(Integer(-123))
4888 >>> a = Any(OctetString(b"hello world").encode())
4889 ANY 040b68656c6c6f20776f726c64
4890 >>> hexenc(bytes(a))
4891 b'0x040x0bhello world'
4893 __slots__ = ("defined",)
4894 tag_default = tag_encode(0)
4895 asn1_type_name = "ANY"
4905 :param value: set the value. Either any kind of pyderasn's
4906 **ready** object, or bytes. Pay attention that
4907 **no** validation is performed is raw binary value
4909 :param bytes expl: override default tag with ``EXPLICIT`` one
4910 :param bool optional: is object ``OPTIONAL`` in sequence
4912 super(Any, self).__init__(None, expl, None, optional, _decoded)
4913 self._value = None if value is None else self._value_sanitize(value)
4916 def _value_sanitize(self, value):
4917 if value.__class__ == binary_type:
4919 if isinstance(value, self.__class__):
4921 if isinstance(value, Obj):
4922 return value.encode()
4923 raise InvalidValueType((self.__class__, Obj, binary_type))
4927 return self._value is not None
4931 if self.expl_lenindef or self.lenindef:
4933 if self.defined is None:
4935 return self.defined[1].bered
4937 def __getstate__(self):
4954 def __setstate__(self, state):
4955 super(Any, self).__setstate__(state)
4956 self._value = state.value
4957 self.defined = state.defined
4959 def __eq__(self, their):
4960 if their.__class__ == binary_type:
4961 return self._value == their
4962 if issubclass(their.__class__, Any):
4963 return self._value == their._value
4972 return self.__class__(
4974 expl=self._expl if expl is None else expl,
4975 optional=self.optional if optional is None else optional,
4978 def __bytes__(self):
4979 self._assert_ready()
4987 self._assert_ready()
4990 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4992 t, tlen, lv = tag_strip(tlv)
4993 except DecodeError as err:
4994 raise err.__class__(
4996 klass=self.__class__,
4997 decode_path=decode_path,
5001 l, llen, v = len_decode(lv)
5002 except LenIndefForm as err:
5003 if not ctx.get("bered", False):
5004 raise err.__class__(
5006 klass=self.__class__,
5007 decode_path=decode_path,
5010 llen, vlen, v = 1, 0, lv[1:]
5011 sub_offset = offset + tlen + llen
5013 while v[:EOC_LEN].tobytes() != EOC:
5014 chunk, v = Any().decode(
5017 decode_path=decode_path + (str(chunk_i),),
5020 _ctx_immutable=False,
5022 vlen += chunk.tlvlen
5023 sub_offset += chunk.tlvlen
5025 tlvlen = tlen + llen + vlen + EOC_LEN
5026 obj = self.__class__(
5027 value=tlv[:tlvlen].tobytes(),
5029 optional=self.optional,
5030 _decoded=(offset, 0, tlvlen),
5033 obj.tag = t.tobytes()
5034 return obj, v[EOC_LEN:]
5035 except DecodeError as err:
5036 raise err.__class__(
5038 klass=self.__class__,
5039 decode_path=decode_path,
5043 raise NotEnoughData(
5044 "encoded length is longer than data",
5045 klass=self.__class__,
5046 decode_path=decode_path,
5049 tlvlen = tlen + llen + l
5050 v, tail = tlv[:tlvlen], v[l:]
5051 obj = self.__class__(
5054 optional=self.optional,
5055 _decoded=(offset, 0, tlvlen),
5057 obj.tag = t.tobytes()
5061 return pp_console_row(next(self.pps()))
5063 def pps(self, decode_path=()):
5066 asn1_type_name=self.asn1_type_name,
5067 obj_name=self.__class__.__name__,
5068 decode_path=decode_path,
5069 blob=self._value if self.ready else None,
5070 optional=self.optional,
5071 default=self == self.default,
5072 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5073 expl=None if self._expl is None else tag_decode(self._expl),
5078 expl_offset=self.expl_offset if self.expled else None,
5079 expl_tlen=self.expl_tlen if self.expled else None,
5080 expl_llen=self.expl_llen if self.expled else None,
5081 expl_vlen=self.expl_vlen if self.expled else None,
5082 expl_lenindef=self.expl_lenindef,
5083 lenindef=self.lenindef,
5086 defined_by, defined = self.defined or (None, None)
5087 if defined_by is not None:
5089 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5091 for pp in self.pps_lenindef(decode_path):
5095 ########################################################################
5096 # ASN.1 constructed types
5097 ########################################################################
5099 def get_def_by_path(defines_by_path, sub_decode_path):
5100 """Get define by decode path
5102 for path, define in defines_by_path:
5103 if len(path) != len(sub_decode_path):
5105 for p1, p2 in zip(path, sub_decode_path):
5106 if (not p1 is any) and (p1 != p2):
5112 def abs_decode_path(decode_path, rel_path):
5113 """Create an absolute decode path from current and relative ones
5115 :param decode_path: current decode path, starting point. Tuple of strings
5116 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5117 If first tuple's element is "/", then treat it as
5118 an absolute path, ignoring ``decode_path`` as
5119 starting point. Also this tuple can contain ".."
5120 elements, stripping the leading element from
5123 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5124 ("foo", "bar", "baz", "whatever")
5125 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5127 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5130 if rel_path[0] == "/":
5132 if rel_path[0] == "..":
5133 return abs_decode_path(decode_path[:-1], rel_path[1:])
5134 return decode_path + rel_path
5137 SequenceState = namedtuple(
5139 BasicState._fields + ("specs", "value",),
5144 class Sequence(Obj):
5145 """``SEQUENCE`` structure type
5147 You have to make specification of sequence::
5149 class Extension(Sequence):
5151 ("extnID", ObjectIdentifier()),
5152 ("critical", Boolean(default=False)),
5153 ("extnValue", OctetString()),
5156 Then, you can work with it as with dictionary.
5158 >>> ext = Extension()
5159 >>> Extension().specs
5161 ('extnID', OBJECT IDENTIFIER),
5162 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5163 ('extnValue', OCTET STRING),
5165 >>> ext["extnID"] = "1.2.3"
5166 Traceback (most recent call last):
5167 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5168 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5170 You can determine if sequence is ready to be encoded:
5175 Traceback (most recent call last):
5176 pyderasn.ObjNotReady: object is not ready: extnValue
5177 >>> ext["extnValue"] = OctetString(b"foobar")
5181 Value you want to assign, must have the same **type** as in
5182 corresponding specification, but it can have different tags,
5183 optional/default attributes -- they will be taken from specification
5186 class TBSCertificate(Sequence):
5188 ("version", Version(expl=tag_ctxc(0), default="v1")),
5191 >>> tbs = TBSCertificate()
5192 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5194 Assign ``None`` to remove value from sequence.
5196 You can set values in Sequence during its initialization:
5198 >>> AlgorithmIdentifier((
5199 ("algorithm", ObjectIdentifier("1.2.3")),
5200 ("parameters", Any(Null()))
5202 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5204 You can determine if value exists/set in the sequence and take its value:
5206 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5209 OBJECT IDENTIFIER 1.2.3
5211 But pay attention that if value has default, then it won't be (not
5212 in) in the sequence (because ``DEFAULT`` must not be encoded in
5213 DER), but you can read its value:
5215 >>> "critical" in ext, ext["critical"]
5216 (False, BOOLEAN False)
5217 >>> ext["critical"] = Boolean(True)
5218 >>> "critical" in ext, ext["critical"]
5219 (True, BOOLEAN True)
5221 All defaulted values are always optional.
5223 .. _allow_default_values_ctx:
5225 DER prohibits default value encoding and will raise an error if
5226 default value is unexpectedly met during decode.
5227 If :ref:`bered <bered_ctx>` context option is set, then no error
5228 will be raised, but ``bered`` attribute set. You can disable strict
5229 defaulted values existence validation by setting
5230 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5232 Two sequences are equal if they have equal specification (schema),
5233 implicit/explicit tagging and the same values.
5235 __slots__ = ("specs",)
5236 tag_default = tag_encode(form=TagFormConstructed, num=16)
5237 asn1_type_name = "SEQUENCE"
5249 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5251 schema = getattr(self, "schema", ())
5253 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
5256 if value is not None:
5257 if issubclass(value.__class__, Sequence):
5258 self._value = value._value
5259 elif hasattr(value, "__iter__"):
5260 for seq_key, seq_value in value:
5261 self[seq_key] = seq_value
5263 raise InvalidValueType((Sequence,))
5264 if default is not None:
5265 if not issubclass(default.__class__, Sequence):
5266 raise InvalidValueType((Sequence,))
5267 default_value = default._value
5268 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5269 default_obj.specs = self.specs
5270 default_obj._value = default_value
5271 self.default = default_obj
5273 self._value = copy(default_obj._value)
5277 for name, spec in iteritems(self.specs):
5278 value = self._value.get(name)
5289 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5291 return any(value.bered for value in itervalues(self._value))
5293 def __getstate__(self):
5294 return SequenceState(
5307 {k: copy(v) for k, v in iteritems(self._value)},
5310 def __setstate__(self, state):
5311 super(Sequence, self).__setstate__(state)
5312 self.specs = state.specs
5313 self._value = state.value
5315 def __eq__(self, their):
5316 if not isinstance(their, self.__class__):
5319 self.specs == their.specs and
5320 self.tag == their.tag and
5321 self._expl == their._expl and
5322 self._value == their._value
5333 return self.__class__(
5336 impl=self.tag if impl is None else impl,
5337 expl=self._expl if expl is None else expl,
5338 default=self.default if default is None else default,
5339 optional=self.optional if optional is None else optional,
5342 def __contains__(self, key):
5343 return key in self._value
5345 def __setitem__(self, key, value):
5346 spec = self.specs.get(key)
5348 raise ObjUnknown(key)
5350 self._value.pop(key, None)
5352 if not isinstance(value, spec.__class__):
5353 raise InvalidValueType((spec.__class__,))
5354 value = spec(value=value)
5355 if spec.default is not None and value == spec.default:
5356 self._value.pop(key, None)
5358 self._value[key] = value
5360 def __getitem__(self, key):
5361 value = self._value.get(key)
5362 if value is not None:
5364 spec = self.specs.get(key)
5366 raise ObjUnknown(key)
5367 if spec.default is not None:
5371 def _values_for_encoding(self):
5372 for name, spec in iteritems(self.specs):
5373 value = self._value.get(name)
5377 raise ObjNotReady(name)
5381 v = b"".join(v.encode() for v in self._values_for_encoding())
5382 return b"".join((self.tag, len_encode(len(v)), v))
5384 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5386 t, tlen, lv = tag_strip(tlv)
5387 except DecodeError as err:
5388 raise err.__class__(
5390 klass=self.__class__,
5391 decode_path=decode_path,
5396 klass=self.__class__,
5397 decode_path=decode_path,
5400 if tag_only: # pragma: no cover
5403 ctx_bered = ctx.get("bered", False)
5405 l, llen, v = len_decode(lv)
5406 except LenIndefForm as err:
5408 raise err.__class__(
5410 klass=self.__class__,
5411 decode_path=decode_path,
5414 l, llen, v = 0, 1, lv[1:]
5416 except DecodeError as err:
5417 raise err.__class__(
5419 klass=self.__class__,
5420 decode_path=decode_path,
5424 raise NotEnoughData(
5425 "encoded length is longer than data",
5426 klass=self.__class__,
5427 decode_path=decode_path,
5431 v, tail = v[:l], v[l:]
5433 sub_offset = offset + tlen + llen
5436 ctx_allow_default_values = ctx.get("allow_default_values", False)
5437 for name, spec in iteritems(self.specs):
5438 if spec.optional and (
5439 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5443 sub_decode_path = decode_path + (name,)
5445 value, v_tail = spec.decode(
5449 decode_path=sub_decode_path,
5451 _ctx_immutable=False,
5453 except TagMismatch as err:
5454 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5458 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5459 if defined is not None:
5460 defined_by, defined_spec = defined
5461 if issubclass(value.__class__, SequenceOf):
5462 for i, _value in enumerate(value):
5463 sub_sub_decode_path = sub_decode_path + (
5465 DecodePathDefBy(defined_by),
5467 defined_value, defined_tail = defined_spec.decode(
5468 memoryview(bytes(_value)),
5470 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5471 if value.expled else (value.tlen + value.llen)
5474 decode_path=sub_sub_decode_path,
5476 _ctx_immutable=False,
5478 if len(defined_tail) > 0:
5481 klass=self.__class__,
5482 decode_path=sub_sub_decode_path,
5485 _value.defined = (defined_by, defined_value)
5487 defined_value, defined_tail = defined_spec.decode(
5488 memoryview(bytes(value)),
5490 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5491 if value.expled else (value.tlen + value.llen)
5494 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5496 _ctx_immutable=False,
5498 if len(defined_tail) > 0:
5501 klass=self.__class__,
5502 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5505 value.defined = (defined_by, defined_value)
5507 value_len = value.fulllen
5509 sub_offset += value_len
5511 if spec.default is not None and value == spec.default:
5512 if ctx_bered or ctx_allow_default_values:
5516 "DEFAULT value met",
5517 klass=self.__class__,
5518 decode_path=sub_decode_path,
5521 values[name] = value
5523 spec_defines = getattr(spec, "defines", ())
5524 if len(spec_defines) == 0:
5525 defines_by_path = ctx.get("defines_by_path", ())
5526 if len(defines_by_path) > 0:
5527 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5528 if spec_defines is not None and len(spec_defines) > 0:
5529 for rel_path, schema in spec_defines:
5530 defined = schema.get(value, None)
5531 if defined is not None:
5532 ctx.setdefault("_defines", []).append((
5533 abs_decode_path(sub_decode_path[:-1], rel_path),
5537 if v[:EOC_LEN].tobytes() != EOC:
5540 klass=self.__class__,
5541 decode_path=decode_path,
5549 klass=self.__class__,
5550 decode_path=decode_path,
5553 obj = self.__class__(
5557 default=self.default,
5558 optional=self.optional,
5559 _decoded=(offset, llen, vlen),
5562 obj.lenindef = lenindef
5563 obj.ber_encoded = ber_encoded
5567 value = pp_console_row(next(self.pps()))
5569 for name in self.specs:
5570 _value = self._value.get(name)
5573 cols.append("%s: %s" % (name, repr(_value)))
5574 return "%s[%s]" % (value, "; ".join(cols))
5576 def pps(self, decode_path=()):
5579 asn1_type_name=self.asn1_type_name,
5580 obj_name=self.__class__.__name__,
5581 decode_path=decode_path,
5582 optional=self.optional,
5583 default=self == self.default,
5584 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5585 expl=None if self._expl is None else tag_decode(self._expl),
5590 expl_offset=self.expl_offset if self.expled else None,
5591 expl_tlen=self.expl_tlen if self.expled else None,
5592 expl_llen=self.expl_llen if self.expled else None,
5593 expl_vlen=self.expl_vlen if self.expled else None,
5594 expl_lenindef=self.expl_lenindef,
5595 lenindef=self.lenindef,
5596 ber_encoded=self.ber_encoded,
5599 for name in self.specs:
5600 value = self._value.get(name)
5603 yield value.pps(decode_path=decode_path + (name,))
5604 for pp in self.pps_lenindef(decode_path):
5608 class Set(Sequence):
5609 """``SET`` structure type
5611 Its usage is identical to :py:class:`pyderasn.Sequence`.
5613 .. _allow_unordered_set_ctx:
5615 DER prohibits unordered values encoding and will raise an error
5616 during decode. If :ref:`bered <bered_ctx>` context option is set,
5617 then no error will occur. Also you can disable strict values
5618 ordering check by setting ``"allow_unordered_set": True``
5619 :ref:`context <ctx>` option.
5622 tag_default = tag_encode(form=TagFormConstructed, num=17)
5623 asn1_type_name = "SET"
5626 raws = [v.encode() for v in self._values_for_encoding()]
5629 return b"".join((self.tag, len_encode(len(v)), v))
5631 def _specs_items(self):
5632 return iteritems(self.specs)
5634 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5636 t, tlen, lv = tag_strip(tlv)
5637 except DecodeError as err:
5638 raise err.__class__(
5640 klass=self.__class__,
5641 decode_path=decode_path,
5646 klass=self.__class__,
5647 decode_path=decode_path,
5653 ctx_bered = ctx.get("bered", False)
5655 l, llen, v = len_decode(lv)
5656 except LenIndefForm as err:
5658 raise err.__class__(
5660 klass=self.__class__,
5661 decode_path=decode_path,
5664 l, llen, v = 0, 1, lv[1:]
5666 except DecodeError as err:
5667 raise err.__class__(
5669 klass=self.__class__,
5670 decode_path=decode_path,
5674 raise NotEnoughData(
5675 "encoded length is longer than data",
5676 klass=self.__class__,
5680 v, tail = v[:l], v[l:]
5682 sub_offset = offset + tlen + llen
5685 ctx_allow_default_values = ctx.get("allow_default_values", False)
5686 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5687 value_prev = memoryview(v[:0])
5690 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5692 for name, spec in self._specs_items():
5693 sub_decode_path = decode_path + (name,)
5699 decode_path=sub_decode_path,
5702 _ctx_immutable=False,
5709 klass=self.__class__,
5710 decode_path=decode_path,
5713 value, v_tail = spec.decode(
5717 decode_path=sub_decode_path,
5719 _ctx_immutable=False,
5721 value_len = value.fulllen
5722 if value_prev.tobytes() > v[:value_len].tobytes():
5723 if ctx_bered or ctx_allow_unordered_set:
5727 "unordered " + self.asn1_type_name,
5728 klass=self.__class__,
5729 decode_path=sub_decode_path,
5732 if spec.default is None or value != spec.default:
5734 elif ctx_bered or ctx_allow_default_values:
5738 "DEFAULT value met",
5739 klass=self.__class__,
5740 decode_path=sub_decode_path,
5743 values[name] = value
5744 value_prev = v[:value_len]
5745 sub_offset += value_len
5748 obj = self.__class__(
5752 default=self.default,
5753 optional=self.optional,
5754 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5757 if v[:EOC_LEN].tobytes() != EOC:
5760 klass=self.__class__,
5761 decode_path=decode_path,
5767 for name, spec in iteritems(self.specs):
5768 if name not in values and not spec.optional:
5770 "%s value is not ready" % name,
5771 klass=self.__class__,
5772 decode_path=decode_path,
5775 obj.ber_encoded = ber_encoded
5779 SequenceOfState = namedtuple(
5781 BasicState._fields + ("spec", "value", "bound_min", "bound_max"),
5786 class SequenceOf(Obj):
5787 """``SEQUENCE OF`` sequence type
5789 For that kind of type you must specify the object it will carry on
5790 (bounds are for example here, not required)::
5792 class Ints(SequenceOf):
5797 >>> ints.append(Integer(123))
5798 >>> ints.append(Integer(234))
5800 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5801 >>> [int(i) for i in ints]
5803 >>> ints.append(Integer(345))
5804 Traceback (most recent call last):
5805 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5808 >>> ints[1] = Integer(345)
5810 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5812 Also you can initialize sequence with preinitialized values:
5814 >>> ints = Ints([Integer(123), Integer(234)])
5816 __slots__ = ("spec", "_bound_min", "_bound_max")
5817 tag_default = tag_encode(form=TagFormConstructed, num=16)
5818 asn1_type_name = "SEQUENCE OF"
5831 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5833 schema = getattr(self, "schema", None)
5835 raise ValueError("schema must be specified")
5837 self._bound_min, self._bound_max = getattr(
5841 ) if bounds is None else bounds
5843 if value is not None:
5844 self._value = self._value_sanitize(value)
5845 if default is not None:
5846 default_value = self._value_sanitize(default)
5847 default_obj = self.__class__(
5852 default_obj._value = default_value
5853 self.default = default_obj
5855 self._value = copy(default_obj._value)
5857 def _value_sanitize(self, value):
5858 if issubclass(value.__class__, SequenceOf):
5859 value = value._value
5860 elif hasattr(value, "__iter__"):
5863 raise InvalidValueType((self.__class__, iter))
5864 if not self._bound_min <= len(value) <= self._bound_max:
5865 raise BoundsError(self._bound_min, len(value), self._bound_max)
5867 if not isinstance(v, self.spec.__class__):
5868 raise InvalidValueType((self.spec.__class__,))
5873 return all(v.ready for v in self._value)
5877 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5879 return any(v.bered for v in self._value)
5881 def __getstate__(self):
5882 return SequenceOfState(
5895 [copy(v) for v in self._value],
5900 def __setstate__(self, state):
5901 super(SequenceOf, self).__setstate__(state)
5902 self.spec = state.spec
5903 self._value = state.value
5904 self._bound_min = state.bound_min
5905 self._bound_max = state.bound_max
5907 def __eq__(self, their):
5908 if isinstance(their, self.__class__):
5910 self.spec == their.spec and
5911 self.tag == their.tag and
5912 self._expl == their._expl and
5913 self._value == their._value
5915 if hasattr(their, "__iter__"):
5916 return self._value == list(their)
5928 return self.__class__(
5932 (self._bound_min, self._bound_max)
5933 if bounds is None else bounds
5935 impl=self.tag if impl is None else impl,
5936 expl=self._expl if expl is None else expl,
5937 default=self.default if default is None else default,
5938 optional=self.optional if optional is None else optional,
5941 def __contains__(self, key):
5942 return key in self._value
5944 def append(self, value):
5945 if not isinstance(value, self.spec.__class__):
5946 raise InvalidValueType((self.spec.__class__,))
5947 if len(self._value) + 1 > self._bound_max:
5950 len(self._value) + 1,
5953 self._value.append(value)
5956 self._assert_ready()
5957 return iter(self._value)
5960 self._assert_ready()
5961 return len(self._value)
5963 def __setitem__(self, key, value):
5964 if not isinstance(value, self.spec.__class__):
5965 raise InvalidValueType((self.spec.__class__,))
5966 self._value[key] = self.spec(value=value)
5968 def __getitem__(self, key):
5969 return self._value[key]
5971 def _values_for_encoding(self):
5972 return iter(self._value)
5975 v = b"".join(v.encode() for v in self._values_for_encoding())
5976 return b"".join((self.tag, len_encode(len(v)), v))
5978 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5980 t, tlen, lv = tag_strip(tlv)
5981 except DecodeError as err:
5982 raise err.__class__(
5984 klass=self.__class__,
5985 decode_path=decode_path,
5990 klass=self.__class__,
5991 decode_path=decode_path,
5997 ctx_bered = ctx.get("bered", False)
5999 l, llen, v = len_decode(lv)
6000 except LenIndefForm as err:
6002 raise err.__class__(
6004 klass=self.__class__,
6005 decode_path=decode_path,
6008 l, llen, v = 0, 1, lv[1:]
6010 except DecodeError as err:
6011 raise err.__class__(
6013 klass=self.__class__,
6014 decode_path=decode_path,
6018 raise NotEnoughData(
6019 "encoded length is longer than data",
6020 klass=self.__class__,
6021 decode_path=decode_path,
6025 v, tail = v[:l], v[l:]
6027 sub_offset = offset + tlen + llen
6029 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6030 value_prev = memoryview(v[:0])
6034 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6036 sub_decode_path = decode_path + (str(len(_value)),)
6037 value, v_tail = spec.decode(
6041 decode_path=sub_decode_path,
6043 _ctx_immutable=False,
6045 value_len = value.fulllen
6047 if value_prev.tobytes() > v[:value_len].tobytes():
6048 if ctx_bered or ctx_allow_unordered_set:
6052 "unordered " + self.asn1_type_name,
6053 klass=self.__class__,
6054 decode_path=sub_decode_path,
6057 value_prev = v[:value_len]
6058 _value.append(value)
6059 sub_offset += value_len
6063 obj = self.__class__(
6066 bounds=(self._bound_min, self._bound_max),
6069 default=self.default,
6070 optional=self.optional,
6071 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6073 except BoundsError as err:
6076 klass=self.__class__,
6077 decode_path=decode_path,
6081 if v[:EOC_LEN].tobytes() != EOC:
6084 klass=self.__class__,
6085 decode_path=decode_path,
6090 obj.ber_encoded = ber_encoded
6095 pp_console_row(next(self.pps())),
6096 ", ".join(repr(v) for v in self._value),
6099 def pps(self, decode_path=()):
6102 asn1_type_name=self.asn1_type_name,
6103 obj_name=self.__class__.__name__,
6104 decode_path=decode_path,
6105 optional=self.optional,
6106 default=self == self.default,
6107 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6108 expl=None if self._expl is None else tag_decode(self._expl),
6113 expl_offset=self.expl_offset if self.expled else None,
6114 expl_tlen=self.expl_tlen if self.expled else None,
6115 expl_llen=self.expl_llen if self.expled else None,
6116 expl_vlen=self.expl_vlen if self.expled else None,
6117 expl_lenindef=self.expl_lenindef,
6118 lenindef=self.lenindef,
6119 ber_encoded=self.ber_encoded,
6122 for i, value in enumerate(self._value):
6123 yield value.pps(decode_path=decode_path + (str(i),))
6124 for pp in self.pps_lenindef(decode_path):
6128 class SetOf(SequenceOf):
6129 """``SET OF`` sequence type
6131 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6134 tag_default = tag_encode(form=TagFormConstructed, num=17)
6135 asn1_type_name = "SET OF"
6138 raws = [v.encode() for v in self._values_for_encoding()]
6141 return b"".join((self.tag, len_encode(len(v)), v))
6143 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6144 return super(SetOf, self)._decode(
6150 ordering_check=True,
6154 def obj_by_path(pypath): # pragma: no cover
6155 """Import object specified as string Python path
6157 Modules must be separated from classes/functions with ``:``.
6159 >>> obj_by_path("foo.bar:Baz")
6160 <class 'foo.bar.Baz'>
6161 >>> obj_by_path("foo.bar:Baz.boo")
6162 <classmethod 'foo.bar.Baz.boo'>
6164 mod, objs = pypath.rsplit(":", 1)
6165 from importlib import import_module
6166 obj = import_module(mod)
6167 for obj_name in objs.split("."):
6168 obj = getattr(obj, obj_name)
6172 def generic_decoder(): # pragma: no cover
6173 # All of this below is a big hack with self references
6174 choice = PrimitiveTypes()
6175 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6176 choice.specs["SetOf"] = SetOf(schema=choice)
6177 for i in six_xrange(31):
6178 choice.specs["SequenceOf%d" % i] = SequenceOf(
6182 choice.specs["Any"] = Any()
6184 # Class name equals to type name, to omit it from output
6185 class SEQUENCEOF(SequenceOf):
6193 with_decode_path=False,
6194 decode_path_only=(),
6196 def _pprint_pps(pps):
6198 if hasattr(pp, "_fields"):
6200 decode_path_only != () and
6201 pp.decode_path[:len(decode_path_only)] != decode_path_only
6204 if pp.asn1_type_name == Choice.asn1_type_name:
6206 pp_kwargs = pp._asdict()
6207 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6208 pp = _pp(**pp_kwargs)
6209 yield pp_console_row(
6214 with_colours=with_colours,
6215 with_decode_path=with_decode_path,
6216 decode_path_len_decrease=len(decode_path_only),
6218 for row in pp_console_blob(
6220 decode_path_len_decrease=len(decode_path_only),
6224 for row in _pprint_pps(pp):
6226 return "\n".join(_pprint_pps(obj.pps()))
6227 return SEQUENCEOF(), pprint_any
6230 def main(): # pragma: no cover
6232 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6233 parser.add_argument(
6237 help="Skip that number of bytes from the beginning",
6239 parser.add_argument(
6241 help="Python paths to dictionary with OIDs, comma separated",
6243 parser.add_argument(
6245 help="Python path to schema definition to use",
6247 parser.add_argument(
6248 "--defines-by-path",
6249 help="Python path to decoder's defines_by_path",
6251 parser.add_argument(
6253 action="store_true",
6254 help="Disallow BER encoding",
6256 parser.add_argument(
6257 "--print-decode-path",
6258 action="store_true",
6259 help="Print decode paths",
6261 parser.add_argument(
6262 "--decode-path-only",
6263 help="Print only specified decode path",
6265 parser.add_argument(
6267 action="store_true",
6268 help="Allow explicit tag out-of-bound",
6270 parser.add_argument(
6272 type=argparse.FileType("rb"),
6273 help="Path to DER file you want to decode",
6275 args = parser.parse_args()
6276 args.DERFile.seek(args.skip)
6277 der = memoryview(args.DERFile.read())
6278 args.DERFile.close()
6280 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6281 if args.oids else ()
6284 schema = obj_by_path(args.schema)
6285 from functools import partial
6286 pprinter = partial(pprint, big_blobs=True)
6288 schema, pprinter = generic_decoder()
6290 "bered": not args.nobered,
6291 "allow_expl_oob": args.allow_expl_oob,
6293 if args.defines_by_path is not None:
6294 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6295 obj, tail = schema().decode(der, ctx=ctx)
6296 from os import environ
6300 with_colours=environ.get("NO_COLOR") is None,
6301 with_decode_path=args.print_decode_path,
6303 () if args.decode_path_only is None else
6304 tuple(args.decode_path_only.split(":"))
6308 print("\nTrailing data: %s" % hexenc(tail))
6311 if __name__ == "__main__":