3 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
4 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU Lesser General Public License as
8 # published by the Free Software Foundation, version 3 of the License.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see <http://www.gnu.org/licenses/>.
17 """Python ASN.1 DER/BER codec with abstract structures
19 This library allows you to marshal various structures in ASN.1 DER
20 format, unmarshal them in BER/CER/DER ones.
24 >>> Integer().decod(raw) == i
27 There are primitive types, holding single values
28 (:py:class:`pyderasn.BitString`,
29 :py:class:`pyderasn.Boolean`,
30 :py:class:`pyderasn.Enumerated`,
31 :py:class:`pyderasn.GeneralizedTime`,
32 :py:class:`pyderasn.Integer`,
33 :py:class:`pyderasn.Null`,
34 :py:class:`pyderasn.ObjectIdentifier`,
35 :py:class:`pyderasn.OctetString`,
36 :py:class:`pyderasn.UTCTime`,
37 :py:class:`various strings <pyderasn.CommonString>`
38 (:py:class:`pyderasn.BMPString`,
39 :py:class:`pyderasn.GeneralString`,
40 :py:class:`pyderasn.GraphicString`,
41 :py:class:`pyderasn.IA5String`,
42 :py:class:`pyderasn.ISO646String`,
43 :py:class:`pyderasn.NumericString`,
44 :py:class:`pyderasn.PrintableString`,
45 :py:class:`pyderasn.T61String`,
46 :py:class:`pyderasn.TeletexString`,
47 :py:class:`pyderasn.UniversalString`,
48 :py:class:`pyderasn.UTF8String`,
49 :py:class:`pyderasn.VideotexString`,
50 :py:class:`pyderasn.VisibleString`)),
51 constructed types, holding multiple primitive types
52 (:py:class:`pyderasn.Sequence`,
53 :py:class:`pyderasn.SequenceOf`,
54 :py:class:`pyderasn.Set`,
55 :py:class:`pyderasn.SetOf`),
56 and special types like
57 :py:class:`pyderasn.Any` and
58 :py:class:`pyderasn.Choice`.
66 Most types in ASN.1 has specific tag for them. ``Obj.tag_default`` is
67 the default tag used during coding process. You can override it with
68 either ``IMPLICIT`` (using either ``impl`` keyword argument or ``impl``
69 class attribute), or ``EXPLICIT`` one (using either ``expl`` keyword
70 argument or ``expl`` class attribute). Both arguments take raw binary
71 string, containing that tag. You can **not** set implicit and explicit
74 There are :py:func:`pyderasn.tag_ctxp` and :py:func:`pyderasn.tag_ctxc`
75 functions, allowing you to easily create ``CONTEXT``
76 ``PRIMITIVE``/``CONSTRUCTED`` tags, by specifying only the required tag
77 number. Pay attention that explicit tags always have *constructed* tag
78 (``tag_ctxc``), but implicit tags for primitive types are primitive
83 >>> Integer(impl=tag_ctxp(1))
85 >>> Integer(expl=tag_ctxc(2))
88 Implicit tag is not explicitly shown.
90 Two objects of the same type, but with different implicit/explicit tags
93 You can get object's effective tag (either default or implicited) through
94 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
97 >>> tag_decode(tag_ctxc(123))
99 >>> klass, form, num = tag_decode(tag_ctxc(123))
100 >>> klass == TagClassContext
102 >>> form == TagFormConstructed
105 To determine if object has explicit tag, use ``expled`` boolean property
106 and ``expl_tag`` property, returning explicit tag's value.
111 Many objects in sequences could be ``OPTIONAL`` and could have
112 ``DEFAULT`` value. You can specify that object's property using
113 corresponding keyword arguments.
115 >>> Integer(optional=True, default=123)
116 INTEGER 123 OPTIONAL DEFAULT
118 Those specifications do not play any role in primitive value encoding,
119 but are taken into account when dealing with sequences holding them. For
120 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
123 class Version(Integer):
129 class TBSCertificate(Sequence):
131 ("version", Version(expl=tag_ctxc(0), default="v1")),
134 When default argument is used and value is not specified, then it equals
142 Some objects give ability to set value size constraints. This is either
143 possible integer value, or allowed length of various strings and
144 sequences. Constraints are set in the following way::
149 And values satisfaction is checked as: ``MIN <= X <= MAX``.
151 For simplicity you can also set bounds the following way::
153 bounded_x = X(bounds=(MIN, MAX))
155 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
161 All objects have ``ready`` boolean property, that tells if object is
162 ready to be encoded. If that kind of action is performed on unready
163 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
165 All objects are friendly to ``copy.copy()`` and copied objects can be
168 Also all objects can be safely ``pickle``-d, but pay attention that
169 pickling among different PyDERASN versions is prohibited.
176 Decoding is performed using :py:meth:`pyderasn.Obj.decode` method.
177 ``offset`` optional argument could be used to set initial object's
178 offset in the binary data, for convenience. It returns decoded object
179 and remaining unmarshalled data (tail). Internally all work is done on
180 ``memoryview(data)``, and you can leave returning tail as a memoryview,
181 by specifying ``leavemm=True`` argument.
183 Also note convenient :py:meth:`pyderasn.Obj.decod` method, that
184 immediately checks and raises if there is non-empty tail.
186 When object is decoded, ``decoded`` property is true and you can safely
187 use following properties:
189 * ``offset`` -- position including initial offset where object's tag starts
190 * ``tlen`` -- length of object's tag
191 * ``llen`` -- length of object's length value
192 * ``vlen`` -- length of object's value
193 * ``tlvlen`` -- length of the whole object
195 Pay attention that those values do **not** include anything related to
196 explicit tag. If you want to know information about it, then use:
198 * ``expled`` -- to know if explicit tag is set
199 * ``expl_offset`` (it is lesser than ``offset``)
202 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
203 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
205 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
208 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
215 You can specify so called context keyword argument during
216 :py:meth:`pyderasn.Obj.decode` invocation. It is dictionary containing
217 various options governing decoding process.
219 Currently available context options:
221 * :ref:`allow_default_values <allow_default_values_ctx>`
222 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
223 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
224 * :ref:`bered <bered_ctx>`
225 * :ref:`defines_by_path <defines_by_path_ctx>`
232 All objects have ``pps()`` method, that is a generator of
233 :py:class:`pyderasn.PP` namedtuple, holding various raw information
234 about the object. If ``pps`` is called on sequences, then all underlying
235 ``PP`` will be yielded.
237 You can use :py:func:`pyderasn.pp_console_row` function, converting
238 those ``PP`` to human readable string. Actually exactly it is used for
239 all object ``repr``. But it is easy to write custom formatters.
241 >>> from pyderasn import pprint
242 >>> encoded = Integer(-12345).encode()
243 >>> obj, tail = Integer().decode(encoded)
244 >>> print(pprint(obj))
245 0 [1,1, 2] INTEGER -12345
249 Example certificate::
251 >>> print(pprint(crt))
252 0 [1,3,1604] Certificate SEQUENCE
253 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
254 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
255 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
256 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
257 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
258 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
260 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
261 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
262 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
263 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
264 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
265 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
266 . . . . . . . 13:02:45:53
268 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
269 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
270 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
272 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
273 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
274 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
279 Let's parse that output, human::
281 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
282 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
283 0 1 2 3 4 5 6 7 8 9 10 11
287 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
293 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
299 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
304 Offset of the object, where its DER/BER encoding begins.
305 Pay attention that it does **not** include explicit tag.
307 If explicit tag exists, then this is its length (tag + encoded length).
309 Length of object's tag. For example CHOICE does not have its own tag,
312 Length of encoded length.
314 Length of encoded value.
316 Visual indentation to show the depth of object in the hierarchy.
318 Object's name inside SEQUENCE/CHOICE.
320 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
321 here. "IMPLICIT" is omitted.
323 Object's class name, if set. Omitted if it is just an ordinary simple
324 value (like with ``algorithm`` in example above).
328 Object's value, if set. Can consist of multiple words (like OCTET/BIT
329 STRINGs above). We see ``v3`` value in Version, because it is named.
330 ``rdnSequence`` is the choice of CHOICE type.
332 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
333 default one, specified in the schema.
335 Shows does object contains any kind of BER encoded data (possibly
336 Sequence holding BER-encoded underlying value).
338 Only applicable to BER encoded data. Indefinite length encoding mark.
340 Only applicable to BER encoded data. If object has BER-specific
341 encoding, then ``BER`` will be shown. It does not depend on indefinite
342 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
343 (and its derivatives), ``SET``, ``SET OF``, ``UTCTime``, ``GeneralizedTime``
352 ASN.1 structures often have ANY and OCTET STRING fields, that are
353 DEFINED BY some previously met ObjectIdentifier. This library provides
354 ability to specify mapping between some OID and field that must be
355 decoded with specific specification.
362 :py:class:`pyderasn.ObjectIdentifier` field inside
363 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
364 necessary for decoding structures. For example, CMS (:rfc:`5652`)
367 class ContentInfo(Sequence):
369 ("contentType", ContentType(defines=((("content",), {
370 id_digestedData: DigestedData(),
371 id_signedData: SignedData(),
373 ("content", Any(expl=tag_ctxc(0))),
376 ``contentType`` field tells that it defines that ``content`` must be
377 decoded with ``SignedData`` specification, if ``contentType`` equals to
378 ``id-signedData``. The same applies to ``DigestedData``. If
379 ``contentType`` contains unknown OID, then no automatic decoding is
382 You can specify multiple fields, that will be autodecoded -- that is why
383 ``defines`` kwarg is a sequence. You can specify defined field
384 relatively or absolutely to current decode path. For example ``defines``
385 for AlgorithmIdentifier of X.509's
386 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
390 id_ecPublicKey: ECParameters(),
391 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
393 (("..", "subjectPublicKey"), {
394 id_rsaEncryption: RSAPublicKey(),
395 id_GostR3410_2001: OctetString(),
399 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
400 autodecode its parameters inside SPKI's algorithm and its public key
403 Following types can be automatically decoded (DEFINED BY):
405 * :py:class:`pyderasn.Any`
406 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
407 * :py:class:`pyderasn.OctetString`
408 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
409 ``Any``/``BitString``/``OctetString``-s
411 When any of those fields is automatically decoded, then ``.defined``
412 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
413 was defined, ``value`` contains corresponding decoded value. For example
414 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
416 .. _defines_by_path_ctx:
418 defines_by_path context option
419 ______________________________
421 Sometimes you either can not or do not want to explicitly set *defines*
422 in the scheme. You can dynamically apply those definitions when calling
423 ``.decode()`` method.
425 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
426 value must be sequence of following tuples::
428 (decode_path, defines)
430 where ``decode_path`` is a tuple holding so-called decode path to the
431 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
432 ``defines``, holding exactly the same value as accepted in its
433 :ref:`keyword argument <defines>`.
435 For example, again for CMS, you want to automatically decode
436 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
437 structures it may hold. Also, automatically decode ``controlSequence``
440 content_info = ContentInfo().decod(data, ctx={"defines_by_path": (
443 ((("content",), {id_signedData: SignedData()}),),
448 DecodePathDefBy(id_signedData),
453 id_cct_PKIData: PKIData(),
454 id_cct_PKIResponse: PKIResponse(),
460 DecodePathDefBy(id_signedData),
463 DecodePathDefBy(id_cct_PKIResponse),
469 id_cmc_recipientNonce: RecipientNonce(),
470 id_cmc_senderNonce: SenderNonce(),
471 id_cmc_statusInfoV2: CMCStatusInfoV2(),
472 id_cmc_transactionId: TransactionId(),
477 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
478 First function is useful for path construction when some automatic
479 decoding is already done. ``any`` means literally any value it meet --
480 useful for SEQUENCE/SET OF-s.
487 By default PyDERASN accepts only DER encoded data. It always encodes to
488 DER. But you can optionally enable BER decoding with setting ``bered``
489 :ref:`context <ctx>` argument to True. Indefinite lengths and
490 constructed primitive types should be parsed successfully.
492 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
493 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
494 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``,
495 ``UTCTime``, ``GeneralizedTime`` can contain it.
496 * If object has an indefinite length encoding, then its ``lenindef``
497 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
498 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
500 * If object has an indefinite length encoded explicit tag, then
501 ``expl_lenindef`` is set to True.
502 * If object has either any of BER-related encoding (explicit tag
503 indefinite length, object's indefinite length, BER-encoding) or any
504 underlying component has that kind of encoding, then ``bered``
505 attribute is set to True. For example SignedData CMS can have
506 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
507 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
509 EOC (end-of-contents) token's length is taken in advance in object's
512 .. _allow_expl_oob_ctx:
514 Allow explicit tag out-of-bound
515 -------------------------------
517 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
518 one value, more than one object. If you set ``allow_expl_oob`` context
519 option to True, then no error will be raised and that invalid encoding
520 will be silently further processed. But pay attention that offsets and
521 lengths will be invalid in that case.
525 This option should be used only for skipping some decode errors, just
526 to see the decoded structure somehow.
530 .. autoclass:: pyderasn.Obj
538 .. autoclass:: pyderasn.Boolean
543 .. autoclass:: pyderasn.Integer
548 .. autoclass:: pyderasn.BitString
553 .. autoclass:: pyderasn.OctetString
558 .. autoclass:: pyderasn.Null
563 .. autoclass:: pyderasn.ObjectIdentifier
568 .. autoclass:: pyderasn.Enumerated
572 .. autoclass:: pyderasn.CommonString
576 .. autoclass:: pyderasn.NumericString
580 .. autoclass:: pyderasn.PrintableString
585 .. autoclass:: pyderasn.UTCTime
586 :members: __init__, todatetime
590 .. autoclass:: pyderasn.GeneralizedTime
597 .. autoclass:: pyderasn.Choice
602 .. autoclass:: PrimitiveTypes
606 .. autoclass:: pyderasn.Any
614 .. autoclass:: pyderasn.Sequence
619 .. autoclass:: pyderasn.Set
624 .. autoclass:: pyderasn.SequenceOf
629 .. autoclass:: pyderasn.SetOf
635 .. autofunction:: pyderasn.abs_decode_path
636 .. autofunction:: pyderasn.colonize_hex
637 .. autofunction:: pyderasn.hexenc
638 .. autofunction:: pyderasn.hexdec
639 .. autofunction:: pyderasn.tag_encode
640 .. autofunction:: pyderasn.tag_decode
641 .. autofunction:: pyderasn.tag_ctxp
642 .. autofunction:: pyderasn.tag_ctxc
643 .. autoclass:: pyderasn.DecodeError
645 .. autoclass:: pyderasn.NotEnoughData
646 .. autoclass:: pyderasn.ExceedingData
647 .. autoclass:: pyderasn.LenIndefForm
648 .. autoclass:: pyderasn.TagMismatch
649 .. autoclass:: pyderasn.InvalidLength
650 .. autoclass:: pyderasn.InvalidOID
651 .. autoclass:: pyderasn.ObjUnknown
652 .. autoclass:: pyderasn.ObjNotReady
653 .. autoclass:: pyderasn.InvalidValueType
654 .. autoclass:: pyderasn.BoundsError
657 from codecs import getdecoder
658 from codecs import getencoder
659 from collections import namedtuple
660 from collections import OrderedDict
661 from copy import copy
662 from datetime import datetime
663 from datetime import timedelta
664 from math import ceil
665 from os import environ
666 from string import ascii_letters
667 from string import digits
668 from unicodedata import category as unicat
670 from six import add_metaclass
671 from six import binary_type
672 from six import byte2int
673 from six import indexbytes
674 from six import int2byte
675 from six import integer_types
676 from six import iterbytes
677 from six import iteritems
678 from six import itervalues
680 from six import string_types
681 from six import text_type
682 from six import unichr as six_unichr
683 from six.moves import xrange as six_xrange
687 from termcolor import colored
688 except ImportError: # pragma: no cover
689 def colored(what, *args, **kwargs):
735 "TagClassApplication",
739 "TagFormConstructed",
750 TagClassUniversal = 0
751 TagClassApplication = 1 << 6
752 TagClassContext = 1 << 7
753 TagClassPrivate = 1 << 6 | 1 << 7
755 TagFormConstructed = 1 << 5
758 TagClassApplication: "APPLICATION ",
759 TagClassPrivate: "PRIVATE ",
760 TagClassUniversal: "UNIV ",
764 LENINDEF = b"\x80" # length indefinite mark
765 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
768 ########################################################################
770 ########################################################################
772 class ASN1Error(ValueError):
776 class DecodeError(ASN1Error):
777 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
779 :param str msg: reason of decode failing
780 :param klass: optional exact DecodeError inherited class (like
781 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
782 :py:exc:`InvalidLength`)
783 :param decode_path: tuple of strings. It contains human
784 readable names of the fields through which
785 decoding process has passed
786 :param int offset: binary offset where failure happened
788 super(DecodeError, self).__init__()
791 self.decode_path = decode_path
797 "" if self.klass is None else self.klass.__name__,
799 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
800 if len(self.decode_path) > 0 else ""
802 ("(at %d)" % self.offset) if self.offset > 0 else "",
808 return "%s(%s)" % (self.__class__.__name__, self)
811 class NotEnoughData(DecodeError):
815 class ExceedingData(ASN1Error):
816 def __init__(self, nbytes):
817 super(ExceedingData, self).__init__()
821 return "%d trailing bytes" % self.nbytes
824 return "%s(%s)" % (self.__class__.__name__, self)
827 class LenIndefForm(DecodeError):
831 class TagMismatch(DecodeError):
835 class InvalidLength(DecodeError):
839 class InvalidOID(DecodeError):
843 class ObjUnknown(ASN1Error):
844 def __init__(self, name):
845 super(ObjUnknown, self).__init__()
849 return "object is unknown: %s" % self.name
852 return "%s(%s)" % (self.__class__.__name__, self)
855 class ObjNotReady(ASN1Error):
856 def __init__(self, name):
857 super(ObjNotReady, self).__init__()
861 return "object is not ready: %s" % self.name
864 return "%s(%s)" % (self.__class__.__name__, self)
867 class InvalidValueType(ASN1Error):
868 def __init__(self, expected_types):
869 super(InvalidValueType, self).__init__()
870 self.expected_types = expected_types
873 return "invalid value type, expected: %s" % ", ".join(
874 [repr(t) for t in self.expected_types]
878 return "%s(%s)" % (self.__class__.__name__, self)
881 class BoundsError(ASN1Error):
882 def __init__(self, bound_min, value, bound_max):
883 super(BoundsError, self).__init__()
884 self.bound_min = bound_min
886 self.bound_max = bound_max
889 return "unsatisfied bounds: %s <= %s <= %s" % (
896 return "%s(%s)" % (self.__class__.__name__, self)
899 ########################################################################
901 ########################################################################
903 _hexdecoder = getdecoder("hex")
904 _hexencoder = getencoder("hex")
908 """Binary data to hexadecimal string convert
910 return _hexdecoder(data)[0]
914 """Hexadecimal string to binary data convert
916 return _hexencoder(data)[0].decode("ascii")
919 def int_bytes_len(num, byte_len=8):
922 return int(ceil(float(num.bit_length()) / byte_len))
925 def zero_ended_encode(num):
926 octets = bytearray(int_bytes_len(num, 7))
928 octets[i] = num & 0x7F
932 octets[i] = 0x80 | (num & 0x7F)
938 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
939 """Encode tag to binary form
941 :param int num: tag's number
942 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
943 :py:data:`pyderasn.TagClassContext`,
944 :py:data:`pyderasn.TagClassApplication`,
945 :py:data:`pyderasn.TagClassPrivate`)
946 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
947 :py:data:`pyderasn.TagFormConstructed`)
951 return int2byte(klass | form | num)
952 # [XX|X|11111][1.......][1.......] ... [0.......]
953 return int2byte(klass | form | 31) + zero_ended_encode(num)
957 """Decode tag from binary form
961 No validation is performed, assuming that it has already passed.
963 It returns tuple with three integers, as
964 :py:func:`pyderasn.tag_encode` accepts.
966 first_octet = byte2int(tag)
967 klass = first_octet & 0xC0
968 form = first_octet & 0x20
969 if first_octet & 0x1F < 0x1F:
970 return (klass, form, first_octet & 0x1F)
972 for octet in iterbytes(tag[1:]):
975 return (klass, form, num)
979 """Create CONTEXT PRIMITIVE tag
981 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
985 """Create CONTEXT CONSTRUCTED tag
987 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
991 """Take off tag from the data
993 :returns: (encoded tag, tag length, remaining data)
996 raise NotEnoughData("no data at all")
997 if byte2int(data) & 0x1F < 31:
998 return data[:1], 1, data[1:]
1003 raise DecodeError("unfinished tag")
1004 if indexbytes(data, i) & 0x80 == 0:
1007 return data[:i], i, data[i:]
1013 octets = bytearray(int_bytes_len(l) + 1)
1014 octets[0] = 0x80 | (len(octets) - 1)
1015 for i in six_xrange(len(octets) - 1, 0, -1):
1016 octets[i] = l & 0xFF
1018 return bytes(octets)
1021 def len_decode(data):
1024 :returns: (decoded length, length's length, remaining data)
1025 :raises LenIndefForm: if indefinite form encoding is met
1028 raise NotEnoughData("no data at all")
1029 first_octet = byte2int(data)
1030 if first_octet & 0x80 == 0:
1031 return first_octet, 1, data[1:]
1032 octets_num = first_octet & 0x7F
1033 if octets_num + 1 > len(data):
1034 raise NotEnoughData("encoded length is longer than data")
1036 raise LenIndefForm()
1037 if byte2int(data[1:]) == 0:
1038 raise DecodeError("leading zeros")
1040 for v in iterbytes(data[1:1 + octets_num]):
1043 raise DecodeError("long form instead of short one")
1044 return l, 1 + octets_num, data[1 + octets_num:]
1047 ########################################################################
1049 ########################################################################
1051 class AutoAddSlots(type):
1052 def __new__(cls, name, bases, _dict):
1053 _dict["__slots__"] = _dict.get("__slots__", ())
1054 return type.__new__(cls, name, bases, _dict)
1057 @add_metaclass(AutoAddSlots)
1059 """Common ASN.1 object class
1061 All ASN.1 types are inherited from it. It has metaclass that
1062 automatically adds ``__slots__`` to all inherited classes.
1086 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1087 self._expl = getattr(self, "expl", None) if expl is None else expl
1088 if self.tag != self.tag_default and self._expl is not None:
1089 raise ValueError("implicit and explicit tags can not be set simultaneously")
1090 if default is not None:
1092 self.optional = optional
1093 self.offset, self.llen, self.vlen = _decoded
1095 self.expl_lenindef = False
1096 self.lenindef = False
1097 self.ber_encoded = False
1100 def ready(self): # pragma: no cover
1101 """Is object ready to be encoded?
1103 raise NotImplementedError()
1105 def _assert_ready(self):
1107 raise ObjNotReady(self.__class__.__name__)
1111 """Is either object or any elements inside is BER encoded?
1113 return self.expl_lenindef or self.lenindef or self.ber_encoded
1117 """Is object decoded?
1119 return (self.llen + self.vlen) > 0
1121 def __getstate__(self): # pragma: no cover
1122 """Used for making safe to be mutable pickleable copies
1124 raise NotImplementedError()
1126 def __setstate__(self, state):
1127 if state.version != __version__:
1128 raise ValueError("data is pickled by different PyDERASN version")
1129 self.tag = self.tag_default
1133 self.optional = False
1137 self.expl_lenindef = False
1138 self.lenindef = False
1139 self.ber_encoded = False
1143 """See :ref:`decoding`
1145 return len(self.tag)
1149 """See :ref:`decoding`
1151 return self.tlen + self.llen + self.vlen
1153 def __str__(self): # pragma: no cover
1154 return self.__bytes__() if PY2 else self.__unicode__()
1156 def __ne__(self, their):
1157 return not(self == their)
1159 def __gt__(self, their): # pragma: no cover
1160 return not(self < their)
1162 def __le__(self, their): # pragma: no cover
1163 return (self == their) or (self < their)
1165 def __ge__(self, their): # pragma: no cover
1166 return (self == their) or (self > their)
1168 def _encode(self): # pragma: no cover
1169 raise NotImplementedError()
1171 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1172 raise NotImplementedError()
1175 """Encode the structure
1177 :returns: DER representation
1179 raw = self._encode()
1180 if self._expl is None:
1182 return b"".join((self._expl, len_encode(len(raw)), raw))
1184 def hexencode(self):
1185 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1187 return hexenc(self.encode())
1197 _ctx_immutable=True,
1201 :param data: either binary or memoryview
1202 :param int offset: initial data's offset
1203 :param bool leavemm: do we need to leave memoryview of remaining
1204 data as is, or convert it to bytes otherwise
1205 :param ctx: optional :ref:`context <ctx>` governing decoding process
1206 :param tag_only: decode only the tag, without length and contents
1207 (used only in Choice and Set structures, trying to
1208 determine if tag satisfies the scheme)
1209 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1211 :returns: (Obj, remaining data)
1213 .. seealso:: :ref:`decoding`
1217 elif _ctx_immutable:
1219 tlv = memoryview(data)
1220 if self._expl is None:
1221 result = self._decode(
1224 decode_path=decode_path,
1233 t, tlen, lv = tag_strip(tlv)
1234 except DecodeError as err:
1235 raise err.__class__(
1237 klass=self.__class__,
1238 decode_path=decode_path,
1243 klass=self.__class__,
1244 decode_path=decode_path,
1248 l, llen, v = len_decode(lv)
1249 except LenIndefForm as err:
1250 if not ctx.get("bered", False):
1251 raise err.__class__(
1253 klass=self.__class__,
1254 decode_path=decode_path,
1258 offset += tlen + llen
1259 result = self._decode(
1262 decode_path=decode_path,
1266 if tag_only: # pragma: no cover
1269 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1270 if eoc_expected.tobytes() != EOC:
1273 klass=self.__class__,
1274 decode_path=decode_path,
1278 obj.expl_lenindef = True
1279 except DecodeError as err:
1280 raise err.__class__(
1282 klass=self.__class__,
1283 decode_path=decode_path,
1288 raise NotEnoughData(
1289 "encoded length is longer than data",
1290 klass=self.__class__,
1291 decode_path=decode_path,
1294 result = self._decode(
1296 offset=offset + tlen + llen,
1297 decode_path=decode_path,
1301 if tag_only: # pragma: no cover
1304 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1306 "explicit tag out-of-bound, longer than data",
1307 klass=self.__class__,
1308 decode_path=decode_path,
1311 return obj, (tail if leavemm else tail.tobytes())
1313 def decod(self, data, offset=0, decode_path=(), ctx=None):
1314 """Decode the data, check that tail is empty
1316 :raises ExceedingData: if tail is not empty
1318 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1319 (decode without tail) that also checks that there is no
1322 obj, tail = self.decode(
1325 decode_path=decode_path,
1330 raise ExceedingData(len(tail))
1333 def hexdecode(self, data, *args, **kwargs):
1334 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1336 return self.decode(hexdec(data), *args, **kwargs)
1338 def hexdecod(self, data, *args, **kwargs):
1339 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1341 return self.decod(hexdec(data), *args, **kwargs)
1345 """See :ref:`decoding`
1347 return self._expl is not None
1351 """See :ref:`decoding`
1356 def expl_tlen(self):
1357 """See :ref:`decoding`
1359 return len(self._expl)
1362 def expl_llen(self):
1363 """See :ref:`decoding`
1365 if self.expl_lenindef:
1367 return len(len_encode(self.tlvlen))
1370 def expl_offset(self):
1371 """See :ref:`decoding`
1373 return self.offset - self.expl_tlen - self.expl_llen
1376 def expl_vlen(self):
1377 """See :ref:`decoding`
1382 def expl_tlvlen(self):
1383 """See :ref:`decoding`
1385 return self.expl_tlen + self.expl_llen + self.expl_vlen
1388 def fulloffset(self):
1389 """See :ref:`decoding`
1391 return self.expl_offset if self.expled else self.offset
1395 """See :ref:`decoding`
1397 return self.expl_tlvlen if self.expled else self.tlvlen
1399 def pps_lenindef(self, decode_path):
1400 if self.lenindef and not (
1401 getattr(self, "defined", None) is not None and
1402 self.defined[1].lenindef
1405 asn1_type_name="EOC",
1407 decode_path=decode_path,
1409 self.offset + self.tlvlen -
1410 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1418 if self.expl_lenindef:
1420 asn1_type_name="EOC",
1421 obj_name="EXPLICIT",
1422 decode_path=decode_path,
1423 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1432 class DecodePathDefBy(object):
1433 """DEFINED BY representation inside decode path
1435 __slots__ = ("defined_by",)
1437 def __init__(self, defined_by):
1438 self.defined_by = defined_by
1440 def __ne__(self, their):
1441 return not(self == their)
1443 def __eq__(self, their):
1444 if not isinstance(their, self.__class__):
1446 return self.defined_by == their.defined_by
1449 return "DEFINED BY " + str(self.defined_by)
1452 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1455 ########################################################################
1457 ########################################################################
1459 PP = namedtuple("PP", (
1487 asn1_type_name="unknown",
1504 expl_lenindef=False,
1535 def _colourize(what, colour, with_colours, attrs=("bold",)):
1536 return colored(what, colour, attrs=attrs) if with_colours else what
1539 def colonize_hex(hexed):
1540 """Separate hexadecimal string with colons
1542 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1551 with_decode_path=False,
1552 decode_path_len_decrease=0,
1559 " " if pp.expl_offset is None else
1560 ("-%d" % (pp.offset - pp.expl_offset))
1562 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1564 col = _colourize(col, "red", with_colours, ())
1565 col += _colourize("B", "red", with_colours) if pp.bered else " "
1567 col = "[%d,%d,%4d]%s" % (
1571 LENINDEF_PP_CHAR if pp.lenindef else " "
1573 col = _colourize(col, "green", with_colours, ())
1575 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1576 if decode_path_len > 0:
1577 cols.append(" ." * decode_path_len)
1578 ent = pp.decode_path[-1]
1579 if isinstance(ent, DecodePathDefBy):
1580 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1581 value = str(ent.defined_by)
1584 len(oid_maps) > 0 and
1585 ent.defined_by.asn1_type_name ==
1586 ObjectIdentifier.asn1_type_name
1588 for oid_map in oid_maps:
1589 oid_name = oid_map.get(value)
1590 if oid_name is not None:
1591 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1593 if oid_name is None:
1594 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1596 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1597 if pp.expl is not None:
1598 klass, _, num = pp.expl
1599 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1600 cols.append(_colourize(col, "blue", with_colours))
1601 if pp.impl is not None:
1602 klass, _, num = pp.impl
1603 col = "[%s%d]" % (TagClassReprs[klass], num)
1604 cols.append(_colourize(col, "blue", with_colours))
1605 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1606 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1608 cols.append(_colourize("BER", "red", with_colours))
1609 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1610 if pp.value is not None:
1612 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1614 len(oid_maps) > 0 and
1615 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1617 for oid_map in oid_maps:
1618 oid_name = oid_map.get(value)
1619 if oid_name is not None:
1620 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1622 if pp.asn1_type_name == Integer.asn1_type_name:
1623 hex_repr = hex(int(pp.obj._value))[2:].upper()
1624 if len(hex_repr) % 2 != 0:
1625 hex_repr = "0" + hex_repr
1626 cols.append(_colourize(
1627 "(%s)" % colonize_hex(hex_repr),
1632 if isinstance(pp.blob, binary_type):
1633 cols.append(hexenc(pp.blob))
1634 elif isinstance(pp.blob, tuple):
1635 cols.append(", ".join(pp.blob))
1637 cols.append(_colourize("OPTIONAL", "red", with_colours))
1639 cols.append(_colourize("DEFAULT", "red", with_colours))
1640 if with_decode_path:
1641 cols.append(_colourize(
1642 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1646 return " ".join(cols)
1649 def pp_console_blob(pp, decode_path_len_decrease=0):
1650 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1651 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1652 if decode_path_len > 0:
1653 cols.append(" ." * (decode_path_len + 1))
1654 if isinstance(pp.blob, binary_type):
1655 blob = hexenc(pp.blob).upper()
1656 for i in six_xrange(0, len(blob), 32):
1657 chunk = blob[i:i + 32]
1658 yield " ".join(cols + [colonize_hex(chunk)])
1659 elif isinstance(pp.blob, tuple):
1660 yield " ".join(cols + [", ".join(pp.blob)])
1668 with_decode_path=False,
1669 decode_path_only=(),
1671 """Pretty print object
1673 :param Obj obj: object you want to pretty print
1674 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1675 Its human readable form is printed when OID is met
1676 :param big_blobs: if large binary objects are met (like OctetString
1677 values), do we need to print them too, on separate
1679 :param with_colours: colourize output, if ``termcolor`` library
1681 :param with_decode_path: print decode path
1682 :param decode_path_only: print only that specified decode path
1684 def _pprint_pps(pps):
1686 if hasattr(pp, "_fields"):
1688 decode_path_only != () and
1690 str(p) for p in pp.decode_path[:len(decode_path_only)]
1691 ) != decode_path_only
1695 yield pp_console_row(
1700 with_colours=with_colours,
1701 with_decode_path=with_decode_path,
1702 decode_path_len_decrease=len(decode_path_only),
1704 for row in pp_console_blob(
1706 decode_path_len_decrease=len(decode_path_only),
1710 yield pp_console_row(
1715 with_colours=with_colours,
1716 with_decode_path=with_decode_path,
1717 decode_path_len_decrease=len(decode_path_only),
1720 for row in _pprint_pps(pp):
1722 return "\n".join(_pprint_pps(obj.pps()))
1725 ########################################################################
1726 # ASN.1 primitive types
1727 ########################################################################
1729 BooleanState = namedtuple("BooleanState", (
1746 """``BOOLEAN`` boolean type
1748 >>> b = Boolean(True)
1750 >>> b == Boolean(True)
1756 tag_default = tag_encode(1)
1757 asn1_type_name = "BOOLEAN"
1769 :param value: set the value. Either boolean type, or
1770 :py:class:`pyderasn.Boolean` object
1771 :param bytes impl: override default tag with ``IMPLICIT`` one
1772 :param bytes expl: override default tag with ``EXPLICIT`` one
1773 :param default: set default value. Type same as in ``value``
1774 :param bool optional: is object ``OPTIONAL`` in sequence
1776 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1777 self._value = None if value is None else self._value_sanitize(value)
1778 if default is not None:
1779 default = self._value_sanitize(default)
1780 self.default = self.__class__(
1786 self._value = default
1788 def _value_sanitize(self, value):
1789 if isinstance(value, bool):
1791 if issubclass(value.__class__, Boolean):
1793 raise InvalidValueType((self.__class__, bool))
1797 return self._value is not None
1799 def __getstate__(self):
1800 return BooleanState(
1815 def __setstate__(self, state):
1816 super(Boolean, self).__setstate__(state)
1817 self._value = state.value
1818 self.tag = state.tag
1819 self._expl = state.expl
1820 self.default = state.default
1821 self.optional = state.optional
1822 self.offset = state.offset
1823 self.llen = state.llen
1824 self.vlen = state.vlen
1825 self.expl_lenindef = state.expl_lenindef
1826 self.lenindef = state.lenindef
1827 self.ber_encoded = state.ber_encoded
1829 def __nonzero__(self):
1830 self._assert_ready()
1834 self._assert_ready()
1837 def __eq__(self, their):
1838 if isinstance(their, bool):
1839 return self._value == their
1840 if not issubclass(their.__class__, Boolean):
1843 self._value == their._value and
1844 self.tag == their.tag and
1845 self._expl == their._expl
1856 return self.__class__(
1858 impl=self.tag if impl is None else impl,
1859 expl=self._expl if expl is None else expl,
1860 default=self.default if default is None else default,
1861 optional=self.optional if optional is None else optional,
1865 self._assert_ready()
1869 (b"\xFF" if self._value else b"\x00"),
1872 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1874 t, _, lv = tag_strip(tlv)
1875 except DecodeError as err:
1876 raise err.__class__(
1878 klass=self.__class__,
1879 decode_path=decode_path,
1884 klass=self.__class__,
1885 decode_path=decode_path,
1891 l, _, v = len_decode(lv)
1892 except DecodeError as err:
1893 raise err.__class__(
1895 klass=self.__class__,
1896 decode_path=decode_path,
1900 raise InvalidLength(
1901 "Boolean's length must be equal to 1",
1902 klass=self.__class__,
1903 decode_path=decode_path,
1907 raise NotEnoughData(
1908 "encoded length is longer than data",
1909 klass=self.__class__,
1910 decode_path=decode_path,
1913 first_octet = byte2int(v)
1915 if first_octet == 0:
1917 elif first_octet == 0xFF:
1919 elif ctx.get("bered", False):
1924 "unacceptable Boolean value",
1925 klass=self.__class__,
1926 decode_path=decode_path,
1929 obj = self.__class__(
1933 default=self.default,
1934 optional=self.optional,
1935 _decoded=(offset, 1, 1),
1937 obj.ber_encoded = ber_encoded
1941 return pp_console_row(next(self.pps()))
1943 def pps(self, decode_path=()):
1946 asn1_type_name=self.asn1_type_name,
1947 obj_name=self.__class__.__name__,
1948 decode_path=decode_path,
1949 value=str(self._value) if self.ready else None,
1950 optional=self.optional,
1951 default=self == self.default,
1952 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1953 expl=None if self._expl is None else tag_decode(self._expl),
1958 expl_offset=self.expl_offset if self.expled else None,
1959 expl_tlen=self.expl_tlen if self.expled else None,
1960 expl_llen=self.expl_llen if self.expled else None,
1961 expl_vlen=self.expl_vlen if self.expled else None,
1962 expl_lenindef=self.expl_lenindef,
1963 ber_encoded=self.ber_encoded,
1966 for pp in self.pps_lenindef(decode_path):
1970 IntegerState = namedtuple("IntegerState", (
1990 """``INTEGER`` integer type
1992 >>> b = Integer(-123)
1994 >>> b == Integer(-123)
1999 >>> Integer(2, bounds=(1, 3))
2001 >>> Integer(5, bounds=(1, 3))
2002 Traceback (most recent call last):
2003 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2007 class Version(Integer):
2014 >>> v = Version("v1")
2021 {'v3': 2, 'v1': 0, 'v2': 1}
2023 __slots__ = ("specs", "_bound_min", "_bound_max")
2024 tag_default = tag_encode(2)
2025 asn1_type_name = "INTEGER"
2039 :param value: set the value. Either integer type, named value
2040 (if ``schema`` is specified in the class), or
2041 :py:class:`pyderasn.Integer` object
2042 :param bounds: set ``(MIN, MAX)`` value constraint.
2043 (-inf, +inf) by default
2044 :param bytes impl: override default tag with ``IMPLICIT`` one
2045 :param bytes expl: override default tag with ``EXPLICIT`` one
2046 :param default: set default value. Type same as in ``value``
2047 :param bool optional: is object ``OPTIONAL`` in sequence
2049 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2051 specs = getattr(self, "schema", {}) if _specs is None else _specs
2052 self.specs = specs if isinstance(specs, dict) else dict(specs)
2053 self._bound_min, self._bound_max = getattr(
2056 (float("-inf"), float("+inf")),
2057 ) if bounds is None else bounds
2058 if value is not None:
2059 self._value = self._value_sanitize(value)
2060 if default is not None:
2061 default = self._value_sanitize(default)
2062 self.default = self.__class__(
2068 if self._value is None:
2069 self._value = default
2071 def _value_sanitize(self, value):
2072 if isinstance(value, integer_types):
2074 elif issubclass(value.__class__, Integer):
2075 value = value._value
2076 elif isinstance(value, str):
2077 value = self.specs.get(value)
2079 raise ObjUnknown("integer value: %s" % value)
2081 raise InvalidValueType((self.__class__, int, str))
2082 if not self._bound_min <= value <= self._bound_max:
2083 raise BoundsError(self._bound_min, value, self._bound_max)
2088 return self._value is not None
2090 def __getstate__(self):
2091 return IntegerState(
2109 def __setstate__(self, state):
2110 super(Integer, self).__setstate__(state)
2111 self.specs = state.specs
2112 self._value = state.value
2113 self._bound_min = state.bound_min
2114 self._bound_max = state.bound_max
2115 self.tag = state.tag
2116 self._expl = state.expl
2117 self.default = state.default
2118 self.optional = state.optional
2119 self.offset = state.offset
2120 self.llen = state.llen
2121 self.vlen = state.vlen
2122 self.expl_lenindef = state.expl_lenindef
2123 self.lenindef = state.lenindef
2124 self.ber_encoded = state.ber_encoded
2127 self._assert_ready()
2128 return int(self._value)
2131 self._assert_ready()
2134 bytes(self._expl or b"") +
2135 str(self._value).encode("ascii"),
2138 def __eq__(self, their):
2139 if isinstance(their, integer_types):
2140 return self._value == their
2141 if not issubclass(their.__class__, Integer):
2144 self._value == their._value and
2145 self.tag == their.tag and
2146 self._expl == their._expl
2149 def __lt__(self, their):
2150 return self._value < their._value
2154 for name, value in iteritems(self.specs):
2155 if value == self._value:
2168 return self.__class__(
2171 (self._bound_min, self._bound_max)
2172 if bounds is None else bounds
2174 impl=self.tag if impl is None else impl,
2175 expl=self._expl if expl is None else expl,
2176 default=self.default if default is None else default,
2177 optional=self.optional if optional is None else optional,
2182 self._assert_ready()
2186 octets = bytearray([0])
2190 octets = bytearray()
2192 octets.append((value & 0xFF) ^ 0xFF)
2194 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2197 octets = bytearray()
2199 octets.append(value & 0xFF)
2201 if octets[-1] & 0x80 > 0:
2204 octets = bytes(octets)
2206 bytes_len = ceil(value.bit_length() / 8) or 1
2209 octets = value.to_bytes(
2214 except OverflowError:
2218 return b"".join((self.tag, len_encode(len(octets)), octets))
2220 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2222 t, _, lv = tag_strip(tlv)
2223 except DecodeError as err:
2224 raise err.__class__(
2226 klass=self.__class__,
2227 decode_path=decode_path,
2232 klass=self.__class__,
2233 decode_path=decode_path,
2239 l, llen, v = len_decode(lv)
2240 except DecodeError as err:
2241 raise err.__class__(
2243 klass=self.__class__,
2244 decode_path=decode_path,
2248 raise NotEnoughData(
2249 "encoded length is longer than data",
2250 klass=self.__class__,
2251 decode_path=decode_path,
2255 raise NotEnoughData(
2257 klass=self.__class__,
2258 decode_path=decode_path,
2261 v, tail = v[:l], v[l:]
2262 first_octet = byte2int(v)
2264 second_octet = byte2int(v[1:])
2266 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2267 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2270 "non normalized integer",
2271 klass=self.__class__,
2272 decode_path=decode_path,
2277 if first_octet & 0x80 > 0:
2278 octets = bytearray()
2279 for octet in bytearray(v):
2280 octets.append(octet ^ 0xFF)
2281 for octet in octets:
2282 value = (value << 8) | octet
2286 for octet in bytearray(v):
2287 value = (value << 8) | octet
2289 value = int.from_bytes(v, byteorder="big", signed=True)
2291 obj = self.__class__(
2293 bounds=(self._bound_min, self._bound_max),
2296 default=self.default,
2297 optional=self.optional,
2299 _decoded=(offset, llen, l),
2301 except BoundsError as err:
2304 klass=self.__class__,
2305 decode_path=decode_path,
2311 return pp_console_row(next(self.pps()))
2313 def pps(self, decode_path=()):
2316 asn1_type_name=self.asn1_type_name,
2317 obj_name=self.__class__.__name__,
2318 decode_path=decode_path,
2319 value=(self.named or str(self._value)) if self.ready else None,
2320 optional=self.optional,
2321 default=self == self.default,
2322 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2323 expl=None if self._expl is None else tag_decode(self._expl),
2328 expl_offset=self.expl_offset if self.expled else None,
2329 expl_tlen=self.expl_tlen if self.expled else None,
2330 expl_llen=self.expl_llen if self.expled else None,
2331 expl_vlen=self.expl_vlen if self.expled else None,
2332 expl_lenindef=self.expl_lenindef,
2335 for pp in self.pps_lenindef(decode_path):
2339 SET01 = frozenset(("0", "1"))
2340 BitStringState = namedtuple("BitStringState", (
2359 class BitString(Obj):
2360 """``BIT STRING`` bit string type
2362 >>> BitString(b"hello world")
2363 BIT STRING 88 bits 68656c6c6f20776f726c64
2366 >>> b == b"hello world"
2371 >>> BitString("'0A3B5F291CD'H")
2372 BIT STRING 44 bits 0a3b5f291cd0
2373 >>> b = BitString("'010110000000'B")
2374 BIT STRING 12 bits 5800
2377 >>> b[0], b[1], b[2], b[3]
2378 (False, True, False, True)
2382 [False, True, False, True, True, False, False, False, False, False, False, False]
2386 class KeyUsage(BitString):
2388 ("digitalSignature", 0),
2389 ("nonRepudiation", 1),
2390 ("keyEncipherment", 2),
2393 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2394 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2396 ['nonRepudiation', 'keyEncipherment']
2398 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2402 Pay attention that BIT STRING can be encoded both in primitive
2403 and constructed forms. Decoder always checks constructed form tag
2404 additionally to specified primitive one. If BER decoding is
2405 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2406 of DER restrictions.
2408 __slots__ = ("tag_constructed", "specs", "defined")
2409 tag_default = tag_encode(3)
2410 asn1_type_name = "BIT STRING"
2423 :param value: set the value. Either binary type, tuple of named
2424 values (if ``schema`` is specified in the class),
2425 string in ``'XXX...'B`` form, or
2426 :py:class:`pyderasn.BitString` object
2427 :param bytes impl: override default tag with ``IMPLICIT`` one
2428 :param bytes expl: override default tag with ``EXPLICIT`` one
2429 :param default: set default value. Type same as in ``value``
2430 :param bool optional: is object ``OPTIONAL`` in sequence
2432 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2433 specs = getattr(self, "schema", {}) if _specs is None else _specs
2434 self.specs = specs if isinstance(specs, dict) else dict(specs)
2435 self._value = None if value is None else self._value_sanitize(value)
2436 if default is not None:
2437 default = self._value_sanitize(default)
2438 self.default = self.__class__(
2444 self._value = default
2446 tag_klass, _, tag_num = tag_decode(self.tag)
2447 self.tag_constructed = tag_encode(
2449 form=TagFormConstructed,
2453 def _bits2octets(self, bits):
2454 if len(self.specs) > 0:
2455 bits = bits.rstrip("0")
2457 bits += "0" * ((8 - (bit_len % 8)) % 8)
2458 octets = bytearray(len(bits) // 8)
2459 for i in six_xrange(len(octets)):
2460 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2461 return bit_len, bytes(octets)
2463 def _value_sanitize(self, value):
2464 if isinstance(value, (string_types, binary_type)):
2466 isinstance(value, string_types) and
2467 value.startswith("'")
2469 if value.endswith("'B"):
2471 if not frozenset(value) <= SET01:
2472 raise ValueError("B's coding contains unacceptable chars")
2473 return self._bits2octets(value)
2474 if value.endswith("'H"):
2478 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2480 if isinstance(value, binary_type):
2481 return (len(value) * 8, value)
2482 raise InvalidValueType((self.__class__, string_types, binary_type))
2483 if isinstance(value, tuple):
2486 isinstance(value[0], integer_types) and
2487 isinstance(value[1], binary_type)
2492 bit = self.specs.get(name)
2494 raise ObjUnknown("BitString value: %s" % name)
2497 return self._bits2octets("")
2498 bits = frozenset(bits)
2499 return self._bits2octets("".join(
2500 ("1" if bit in bits else "0")
2501 for bit in six_xrange(max(bits) + 1)
2503 if issubclass(value.__class__, BitString):
2505 raise InvalidValueType((self.__class__, binary_type, string_types))
2509 return self._value is not None
2511 def __getstate__(self):
2512 return BitStringState(
2526 self.tag_constructed,
2530 def __setstate__(self, state):
2531 super(BitString, self).__setstate__(state)
2532 self.specs = state.specs
2533 self._value = state.value
2534 self.tag = state.tag
2535 self._expl = state.expl
2536 self.default = state.default
2537 self.optional = state.optional
2538 self.offset = state.offset
2539 self.llen = state.llen
2540 self.vlen = state.vlen
2541 self.expl_lenindef = state.expl_lenindef
2542 self.lenindef = state.lenindef
2543 self.ber_encoded = state.ber_encoded
2544 self.tag_constructed = state.tag_constructed
2545 self.defined = state.defined
2548 self._assert_ready()
2549 for i in six_xrange(self._value[0]):
2554 self._assert_ready()
2555 return self._value[0]
2557 def __bytes__(self):
2558 self._assert_ready()
2559 return self._value[1]
2561 def __eq__(self, their):
2562 if isinstance(their, bytes):
2563 return self._value[1] == their
2564 if not issubclass(their.__class__, BitString):
2567 self._value == their._value and
2568 self.tag == their.tag and
2569 self._expl == their._expl
2574 return [name for name, bit in iteritems(self.specs) if self[bit]]
2584 return self.__class__(
2586 impl=self.tag if impl is None else impl,
2587 expl=self._expl if expl is None else expl,
2588 default=self.default if default is None else default,
2589 optional=self.optional if optional is None else optional,
2593 def __getitem__(self, key):
2594 if isinstance(key, int):
2595 bit_len, octets = self._value
2599 byte2int(memoryview(octets)[key // 8:]) >>
2602 if isinstance(key, string_types):
2603 value = self.specs.get(key)
2605 raise ObjUnknown("BitString value: %s" % key)
2607 raise InvalidValueType((int, str))
2610 self._assert_ready()
2611 bit_len, octets = self._value
2614 len_encode(len(octets) + 1),
2615 int2byte((8 - bit_len % 8) % 8),
2619 def _decode_chunk(self, lv, offset, decode_path):
2621 l, llen, v = len_decode(lv)
2622 except DecodeError as err:
2623 raise err.__class__(
2625 klass=self.__class__,
2626 decode_path=decode_path,
2630 raise NotEnoughData(
2631 "encoded length is longer than data",
2632 klass=self.__class__,
2633 decode_path=decode_path,
2637 raise NotEnoughData(
2639 klass=self.__class__,
2640 decode_path=decode_path,
2643 pad_size = byte2int(v)
2644 if l == 1 and pad_size != 0:
2646 "invalid empty value",
2647 klass=self.__class__,
2648 decode_path=decode_path,
2654 klass=self.__class__,
2655 decode_path=decode_path,
2658 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2661 klass=self.__class__,
2662 decode_path=decode_path,
2665 v, tail = v[:l], v[l:]
2666 obj = self.__class__(
2667 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2670 default=self.default,
2671 optional=self.optional,
2673 _decoded=(offset, llen, l),
2677 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2679 t, tlen, lv = tag_strip(tlv)
2680 except DecodeError as err:
2681 raise err.__class__(
2683 klass=self.__class__,
2684 decode_path=decode_path,
2688 if tag_only: # pragma: no cover
2690 return self._decode_chunk(lv, offset, decode_path)
2691 if t == self.tag_constructed:
2692 if not ctx.get("bered", False):
2694 "unallowed BER constructed encoding",
2695 klass=self.__class__,
2696 decode_path=decode_path,
2699 if tag_only: # pragma: no cover
2703 l, llen, v = len_decode(lv)
2704 except LenIndefForm:
2705 llen, l, v = 1, 0, lv[1:]
2707 except DecodeError as err:
2708 raise err.__class__(
2710 klass=self.__class__,
2711 decode_path=decode_path,
2715 raise NotEnoughData(
2716 "encoded length is longer than data",
2717 klass=self.__class__,
2718 decode_path=decode_path,
2721 if not lenindef and l == 0:
2722 raise NotEnoughData(
2724 klass=self.__class__,
2725 decode_path=decode_path,
2729 sub_offset = offset + tlen + llen
2733 if v[:EOC_LEN].tobytes() == EOC:
2740 "chunk out of bounds",
2741 klass=self.__class__,
2742 decode_path=decode_path + (str(len(chunks) - 1),),
2743 offset=chunks[-1].offset,
2745 sub_decode_path = decode_path + (str(len(chunks)),)
2747 chunk, v_tail = BitString().decode(
2750 decode_path=sub_decode_path,
2753 _ctx_immutable=False,
2757 "expected BitString encoded chunk",
2758 klass=self.__class__,
2759 decode_path=sub_decode_path,
2762 chunks.append(chunk)
2763 sub_offset += chunk.tlvlen
2764 vlen += chunk.tlvlen
2766 if len(chunks) == 0:
2769 klass=self.__class__,
2770 decode_path=decode_path,
2775 for chunk_i, chunk in enumerate(chunks[:-1]):
2776 if chunk.bit_len % 8 != 0:
2778 "BitString chunk is not multiple of 8 bits",
2779 klass=self.__class__,
2780 decode_path=decode_path + (str(chunk_i),),
2781 offset=chunk.offset,
2783 values.append(bytes(chunk))
2784 bit_len += chunk.bit_len
2785 chunk_last = chunks[-1]
2786 values.append(bytes(chunk_last))
2787 bit_len += chunk_last.bit_len
2788 obj = self.__class__(
2789 value=(bit_len, b"".join(values)),
2792 default=self.default,
2793 optional=self.optional,
2795 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2797 obj.lenindef = lenindef
2798 obj.ber_encoded = True
2799 return obj, (v[EOC_LEN:] if lenindef else v)
2801 klass=self.__class__,
2802 decode_path=decode_path,
2807 return pp_console_row(next(self.pps()))
2809 def pps(self, decode_path=()):
2813 bit_len, blob = self._value
2814 value = "%d bits" % bit_len
2815 if len(self.specs) > 0:
2816 blob = tuple(self.named)
2819 asn1_type_name=self.asn1_type_name,
2820 obj_name=self.__class__.__name__,
2821 decode_path=decode_path,
2824 optional=self.optional,
2825 default=self == self.default,
2826 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2827 expl=None if self._expl is None else tag_decode(self._expl),
2832 expl_offset=self.expl_offset if self.expled else None,
2833 expl_tlen=self.expl_tlen if self.expled else None,
2834 expl_llen=self.expl_llen if self.expled else None,
2835 expl_vlen=self.expl_vlen if self.expled else None,
2836 expl_lenindef=self.expl_lenindef,
2837 lenindef=self.lenindef,
2838 ber_encoded=self.ber_encoded,
2841 defined_by, defined = self.defined or (None, None)
2842 if defined_by is not None:
2844 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2846 for pp in self.pps_lenindef(decode_path):
2850 OctetStringState = namedtuple("OctetStringState", (
2870 class OctetString(Obj):
2871 """``OCTET STRING`` binary string type
2873 >>> s = OctetString(b"hello world")
2874 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2875 >>> s == OctetString(b"hello world")
2880 >>> OctetString(b"hello", bounds=(4, 4))
2881 Traceback (most recent call last):
2882 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2883 >>> OctetString(b"hell", bounds=(4, 4))
2884 OCTET STRING 4 bytes 68656c6c
2888 Pay attention that OCTET STRING can be encoded both in primitive
2889 and constructed forms. Decoder always checks constructed form tag
2890 additionally to specified primitive one. If BER decoding is
2891 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2892 of DER restrictions.
2894 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2895 tag_default = tag_encode(4)
2896 asn1_type_name = "OCTET STRING"
2910 :param value: set the value. Either binary type, or
2911 :py:class:`pyderasn.OctetString` object
2912 :param bounds: set ``(MIN, MAX)`` value size constraint.
2913 (-inf, +inf) by default
2914 :param bytes impl: override default tag with ``IMPLICIT`` one
2915 :param bytes expl: override default tag with ``EXPLICIT`` one
2916 :param default: set default value. Type same as in ``value``
2917 :param bool optional: is object ``OPTIONAL`` in sequence
2919 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2921 self._bound_min, self._bound_max = getattr(
2925 ) if bounds is None else bounds
2926 if value is not None:
2927 self._value = self._value_sanitize(value)
2928 if default is not None:
2929 default = self._value_sanitize(default)
2930 self.default = self.__class__(
2935 if self._value is None:
2936 self._value = default
2938 tag_klass, _, tag_num = tag_decode(self.tag)
2939 self.tag_constructed = tag_encode(
2941 form=TagFormConstructed,
2945 def _value_sanitize(self, value):
2946 if isinstance(value, binary_type):
2948 elif issubclass(value.__class__, OctetString):
2949 value = value._value
2951 raise InvalidValueType((self.__class__, bytes))
2952 if not self._bound_min <= len(value) <= self._bound_max:
2953 raise BoundsError(self._bound_min, len(value), self._bound_max)
2958 return self._value is not None
2960 def __getstate__(self):
2961 return OctetStringState(
2976 self.tag_constructed,
2980 def __setstate__(self, state):
2981 super(OctetString, self).__setstate__(state)
2982 self._value = state.value
2983 self._bound_min = state.bound_min
2984 self._bound_max = state.bound_max
2985 self.tag = state.tag
2986 self._expl = state.expl
2987 self.default = state.default
2988 self.optional = state.optional
2989 self.offset = state.offset
2990 self.llen = state.llen
2991 self.vlen = state.vlen
2992 self.expl_lenindef = state.expl_lenindef
2993 self.lenindef = state.lenindef
2994 self.ber_encoded = state.ber_encoded
2995 self.tag_constructed = state.tag_constructed
2996 self.defined = state.defined
2998 def __bytes__(self):
2999 self._assert_ready()
3002 def __eq__(self, their):
3003 if isinstance(their, binary_type):
3004 return self._value == their
3005 if not issubclass(their.__class__, OctetString):
3008 self._value == their._value and
3009 self.tag == their.tag and
3010 self._expl == their._expl
3013 def __lt__(self, their):
3014 return self._value < their._value
3025 return self.__class__(
3028 (self._bound_min, self._bound_max)
3029 if bounds is None else bounds
3031 impl=self.tag if impl is None else impl,
3032 expl=self._expl if expl is None else expl,
3033 default=self.default if default is None else default,
3034 optional=self.optional if optional is None else optional,
3038 self._assert_ready()
3041 len_encode(len(self._value)),
3045 def _decode_chunk(self, lv, offset, decode_path, ctx):
3047 l, llen, v = len_decode(lv)
3048 except DecodeError as err:
3049 raise err.__class__(
3051 klass=self.__class__,
3052 decode_path=decode_path,
3056 raise NotEnoughData(
3057 "encoded length is longer than data",
3058 klass=self.__class__,
3059 decode_path=decode_path,
3062 v, tail = v[:l], v[l:]
3064 obj = self.__class__(
3066 bounds=(self._bound_min, self._bound_max),
3069 default=self.default,
3070 optional=self.optional,
3071 _decoded=(offset, llen, l),
3074 except DecodeError as err:
3077 klass=self.__class__,
3078 decode_path=decode_path,
3081 except BoundsError as err:
3084 klass=self.__class__,
3085 decode_path=decode_path,
3090 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3092 t, tlen, lv = tag_strip(tlv)
3093 except DecodeError as err:
3094 raise err.__class__(
3096 klass=self.__class__,
3097 decode_path=decode_path,
3103 return self._decode_chunk(lv, offset, decode_path, ctx)
3104 if t == self.tag_constructed:
3105 if not ctx.get("bered", False):
3107 "unallowed BER constructed encoding",
3108 klass=self.__class__,
3109 decode_path=decode_path,
3116 l, llen, v = len_decode(lv)
3117 except LenIndefForm:
3118 llen, l, v = 1, 0, lv[1:]
3120 except DecodeError as err:
3121 raise err.__class__(
3123 klass=self.__class__,
3124 decode_path=decode_path,
3128 raise NotEnoughData(
3129 "encoded length is longer than data",
3130 klass=self.__class__,
3131 decode_path=decode_path,
3135 sub_offset = offset + tlen + llen
3139 if v[:EOC_LEN].tobytes() == EOC:
3146 "chunk out of bounds",
3147 klass=self.__class__,
3148 decode_path=decode_path + (str(len(chunks) - 1),),
3149 offset=chunks[-1].offset,
3151 sub_decode_path = decode_path + (str(len(chunks)),)
3153 chunk, v_tail = OctetString().decode(
3156 decode_path=sub_decode_path,
3159 _ctx_immutable=False,
3163 "expected OctetString encoded chunk",
3164 klass=self.__class__,
3165 decode_path=sub_decode_path,
3168 chunks.append(chunk)
3169 sub_offset += chunk.tlvlen
3170 vlen += chunk.tlvlen
3173 obj = self.__class__(
3174 value=b"".join(bytes(chunk) for chunk in chunks),
3175 bounds=(self._bound_min, self._bound_max),
3178 default=self.default,
3179 optional=self.optional,
3180 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3183 except DecodeError as err:
3186 klass=self.__class__,
3187 decode_path=decode_path,
3190 except BoundsError as err:
3193 klass=self.__class__,
3194 decode_path=decode_path,
3197 obj.lenindef = lenindef
3198 obj.ber_encoded = True
3199 return obj, (v[EOC_LEN:] if lenindef else v)
3201 klass=self.__class__,
3202 decode_path=decode_path,
3207 return pp_console_row(next(self.pps()))
3209 def pps(self, decode_path=()):
3212 asn1_type_name=self.asn1_type_name,
3213 obj_name=self.__class__.__name__,
3214 decode_path=decode_path,
3215 value=("%d bytes" % len(self._value)) if self.ready else None,
3216 blob=self._value if self.ready else None,
3217 optional=self.optional,
3218 default=self == self.default,
3219 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3220 expl=None if self._expl is None else tag_decode(self._expl),
3225 expl_offset=self.expl_offset if self.expled else None,
3226 expl_tlen=self.expl_tlen if self.expled else None,
3227 expl_llen=self.expl_llen if self.expled else None,
3228 expl_vlen=self.expl_vlen if self.expled else None,
3229 expl_lenindef=self.expl_lenindef,
3230 lenindef=self.lenindef,
3231 ber_encoded=self.ber_encoded,
3234 defined_by, defined = self.defined or (None, None)
3235 if defined_by is not None:
3237 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3239 for pp in self.pps_lenindef(decode_path):
3243 NullState = namedtuple("NullState", (
3259 """``NULL`` null object
3267 tag_default = tag_encode(5)
3268 asn1_type_name = "NULL"
3272 value=None, # unused, but Sequence passes it
3279 :param bytes impl: override default tag with ``IMPLICIT`` one
3280 :param bytes expl: override default tag with ``EXPLICIT`` one
3281 :param bool optional: is object ``OPTIONAL`` in sequence
3283 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3290 def __getstate__(self):
3305 def __setstate__(self, state):
3306 super(Null, self).__setstate__(state)
3307 self.tag = state.tag
3308 self._expl = state.expl
3309 self.default = state.default
3310 self.optional = state.optional
3311 self.offset = state.offset
3312 self.llen = state.llen
3313 self.vlen = state.vlen
3314 self.expl_lenindef = state.expl_lenindef
3315 self.lenindef = state.lenindef
3316 self.ber_encoded = state.ber_encoded
3318 def __eq__(self, their):
3319 if not issubclass(their.__class__, Null):
3322 self.tag == their.tag and
3323 self._expl == their._expl
3333 return self.__class__(
3334 impl=self.tag if impl is None else impl,
3335 expl=self._expl if expl is None else expl,
3336 optional=self.optional if optional is None else optional,
3340 return self.tag + len_encode(0)
3342 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3344 t, _, lv = tag_strip(tlv)
3345 except DecodeError as err:
3346 raise err.__class__(
3348 klass=self.__class__,
3349 decode_path=decode_path,
3354 klass=self.__class__,
3355 decode_path=decode_path,
3358 if tag_only: # pragma: no cover
3361 l, _, v = len_decode(lv)
3362 except DecodeError as err:
3363 raise err.__class__(
3365 klass=self.__class__,
3366 decode_path=decode_path,
3370 raise InvalidLength(
3371 "Null must have zero length",
3372 klass=self.__class__,
3373 decode_path=decode_path,
3376 obj = self.__class__(
3379 optional=self.optional,
3380 _decoded=(offset, 1, 0),
3385 return pp_console_row(next(self.pps()))
3387 def pps(self, decode_path=()):
3390 asn1_type_name=self.asn1_type_name,
3391 obj_name=self.__class__.__name__,
3392 decode_path=decode_path,
3393 optional=self.optional,
3394 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3395 expl=None if self._expl is None else tag_decode(self._expl),
3400 expl_offset=self.expl_offset if self.expled else None,
3401 expl_tlen=self.expl_tlen if self.expled else None,
3402 expl_llen=self.expl_llen if self.expled else None,
3403 expl_vlen=self.expl_vlen if self.expled else None,
3404 expl_lenindef=self.expl_lenindef,
3407 for pp in self.pps_lenindef(decode_path):
3411 ObjectIdentifierState = namedtuple("ObjectIdentifierState", (
3430 if (value[0] in "+- ") or (value[-1] == " "):
3431 raise ValueError("non-pure integer")
3435 class ObjectIdentifier(Obj):
3436 """``OBJECT IDENTIFIER`` OID type
3438 >>> oid = ObjectIdentifier((1, 2, 3))
3439 OBJECT IDENTIFIER 1.2.3
3440 >>> oid == ObjectIdentifier("1.2.3")
3446 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3447 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3449 >>> str(ObjectIdentifier((3, 1)))
3450 Traceback (most recent call last):
3451 pyderasn.InvalidOID: unacceptable first arc value
3453 __slots__ = ("defines",)
3454 tag_default = tag_encode(6)
3455 asn1_type_name = "OBJECT IDENTIFIER"
3468 :param value: set the value. Either tuples of integers,
3469 string of "."-concatenated integers, or
3470 :py:class:`pyderasn.ObjectIdentifier` object
3471 :param defines: sequence of tuples. Each tuple has two elements.
3472 First one is relative to current one decode
3473 path, aiming to the field defined by that OID.
3474 Read about relative path in
3475 :py:func:`pyderasn.abs_decode_path`. Second
3476 tuple element is ``{OID: pyderasn.Obj()}``
3477 dictionary, mapping between current OID value
3478 and structure applied to defined field.
3479 :ref:`Read about DEFINED BY <definedby>`
3480 :param bytes impl: override default tag with ``IMPLICIT`` one
3481 :param bytes expl: override default tag with ``EXPLICIT`` one
3482 :param default: set default value. Type same as in ``value``
3483 :param bool optional: is object ``OPTIONAL`` in sequence
3485 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3487 if value is not None:
3488 self._value = self._value_sanitize(value)
3489 if default is not None:
3490 default = self._value_sanitize(default)
3491 self.default = self.__class__(
3496 if self._value is None:
3497 self._value = default
3498 self.defines = defines
3500 def __add__(self, their):
3501 if isinstance(their, self.__class__):
3502 return self.__class__(self._value + their._value)
3503 if isinstance(their, tuple):
3504 return self.__class__(self._value + their)
3505 raise InvalidValueType((self.__class__, tuple))
3507 def _value_sanitize(self, value):
3508 if issubclass(value.__class__, ObjectIdentifier):
3510 if isinstance(value, string_types):
3512 value = tuple(pureint(arc) for arc in value.split("."))
3514 raise InvalidOID("unacceptable arcs values")
3515 if isinstance(value, tuple):
3517 raise InvalidOID("less than 2 arcs")
3518 first_arc = value[0]
3519 if first_arc in (0, 1):
3520 if not (0 <= value[1] <= 39):
3521 raise InvalidOID("second arc is too wide")
3522 elif first_arc == 2:
3525 raise InvalidOID("unacceptable first arc value")
3526 if not all(arc >= 0 for arc in value):
3527 raise InvalidOID("negative arc value")
3529 raise InvalidValueType((self.__class__, str, tuple))
3533 return self._value is not None
3535 def __getstate__(self):
3536 return ObjectIdentifierState(
3552 def __setstate__(self, state):
3553 super(ObjectIdentifier, self).__setstate__(state)
3554 self._value = state.value
3555 self.tag = state.tag
3556 self._expl = state.expl
3557 self.default = state.default
3558 self.optional = state.optional
3559 self.offset = state.offset
3560 self.llen = state.llen
3561 self.vlen = state.vlen
3562 self.expl_lenindef = state.expl_lenindef
3563 self.lenindef = state.lenindef
3564 self.ber_encoded = state.ber_encoded
3565 self.defines = state.defines
3568 self._assert_ready()
3569 return iter(self._value)
3572 return ".".join(str(arc) for arc in self._value or ())
3575 self._assert_ready()
3578 bytes(self._expl or b"") +
3579 str(self._value).encode("ascii"),
3582 def __eq__(self, their):
3583 if isinstance(their, tuple):
3584 return self._value == their
3585 if not issubclass(their.__class__, ObjectIdentifier):
3588 self.tag == their.tag and
3589 self._expl == their._expl and
3590 self._value == their._value
3593 def __lt__(self, their):
3594 return self._value < their._value
3605 return self.__class__(
3607 defines=self.defines if defines is None else defines,
3608 impl=self.tag if impl is None else impl,
3609 expl=self._expl if expl is None else expl,
3610 default=self.default if default is None else default,
3611 optional=self.optional if optional is None else optional,
3615 self._assert_ready()
3617 first_value = value[1]
3618 first_arc = value[0]
3621 elif first_arc == 1:
3623 elif first_arc == 2:
3625 else: # pragma: no cover
3626 raise RuntimeError("invalid arc is stored")
3627 octets = [zero_ended_encode(first_value)]
3628 for arc in value[2:]:
3629 octets.append(zero_ended_encode(arc))
3630 v = b"".join(octets)
3631 return b"".join((self.tag, len_encode(len(v)), v))
3633 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3635 t, _, lv = tag_strip(tlv)
3636 except DecodeError as err:
3637 raise err.__class__(
3639 klass=self.__class__,
3640 decode_path=decode_path,
3645 klass=self.__class__,
3646 decode_path=decode_path,
3649 if tag_only: # pragma: no cover
3652 l, llen, v = len_decode(lv)
3653 except DecodeError as err:
3654 raise err.__class__(
3656 klass=self.__class__,
3657 decode_path=decode_path,
3661 raise NotEnoughData(
3662 "encoded length is longer than data",
3663 klass=self.__class__,
3664 decode_path=decode_path,
3668 raise NotEnoughData(
3670 klass=self.__class__,
3671 decode_path=decode_path,
3674 v, tail = v[:l], v[l:]
3681 octet = indexbytes(v, i)
3682 if i == 0 and octet == 0x80:
3683 if ctx.get("bered", False):
3686 raise DecodeError("non normalized arc encoding")
3687 arc = (arc << 7) | (octet & 0x7F)
3688 if octet & 0x80 == 0:
3696 klass=self.__class__,
3697 decode_path=decode_path,
3701 second_arc = arcs[0]
3702 if 0 <= second_arc <= 39:
3704 elif 40 <= second_arc <= 79:
3710 obj = self.__class__(
3711 value=tuple([first_arc, second_arc] + arcs[1:]),
3714 default=self.default,
3715 optional=self.optional,
3716 _decoded=(offset, llen, l),
3719 obj.ber_encoded = True
3723 return pp_console_row(next(self.pps()))
3725 def pps(self, decode_path=()):
3728 asn1_type_name=self.asn1_type_name,
3729 obj_name=self.__class__.__name__,
3730 decode_path=decode_path,
3731 value=str(self) if self.ready else None,
3732 optional=self.optional,
3733 default=self == self.default,
3734 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3735 expl=None if self._expl is None else tag_decode(self._expl),
3740 expl_offset=self.expl_offset if self.expled else None,
3741 expl_tlen=self.expl_tlen if self.expled else None,
3742 expl_llen=self.expl_llen if self.expled else None,
3743 expl_vlen=self.expl_vlen if self.expled else None,
3744 expl_lenindef=self.expl_lenindef,
3745 ber_encoded=self.ber_encoded,
3748 for pp in self.pps_lenindef(decode_path):
3752 class Enumerated(Integer):
3753 """``ENUMERATED`` integer type
3755 This type is identical to :py:class:`pyderasn.Integer`, but requires
3756 schema to be specified and does not accept values missing from it.
3759 tag_default = tag_encode(10)
3760 asn1_type_name = "ENUMERATED"
3771 bounds=None, # dummy argument, workability for Integer.decode
3773 super(Enumerated, self).__init__(
3774 value, bounds, impl, expl, default, optional, _specs, _decoded,
3776 if len(self.specs) == 0:
3777 raise ValueError("schema must be specified")
3779 def _value_sanitize(self, value):
3780 if isinstance(value, self.__class__):
3781 value = value._value
3782 elif isinstance(value, integer_types):
3783 for _value in itervalues(self.specs):
3788 "unknown integer value: %s" % value,
3789 klass=self.__class__,
3791 elif isinstance(value, string_types):
3792 value = self.specs.get(value)
3794 raise ObjUnknown("integer value: %s" % value)
3796 raise InvalidValueType((self.__class__, int, str))
3808 return self.__class__(
3810 impl=self.tag if impl is None else impl,
3811 expl=self._expl if expl is None else expl,
3812 default=self.default if default is None else default,
3813 optional=self.optional if optional is None else optional,
3818 def escape_control_unicode(c):
3819 if unicat(c).startswith("C"):
3820 c = repr(c).lstrip("u").strip("'")
3824 class CommonString(OctetString):
3825 """Common class for all strings
3827 Everything resembles :py:class:`pyderasn.OctetString`, except
3828 ability to deal with unicode text strings.
3830 >>> hexenc("привет мир".encode("utf-8"))
3831 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3832 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3834 >>> s = UTF8String("привет мир")
3835 UTF8String UTF8String привет мир
3837 'привет мир'
3838 >>> hexenc(bytes(s))
3839 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3841 >>> PrintableString("привет мир")
3842 Traceback (most recent call last):
3843 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3845 >>> BMPString("ада", bounds=(2, 2))
3846 Traceback (most recent call last):
3847 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3848 >>> s = BMPString("ад", bounds=(2, 2))
3851 >>> hexenc(bytes(s))
3859 * - :py:class:`pyderasn.UTF8String`
3861 * - :py:class:`pyderasn.NumericString`
3863 * - :py:class:`pyderasn.PrintableString`
3865 * - :py:class:`pyderasn.TeletexString`
3867 * - :py:class:`pyderasn.T61String`
3869 * - :py:class:`pyderasn.VideotexString`
3871 * - :py:class:`pyderasn.IA5String`
3873 * - :py:class:`pyderasn.GraphicString`
3875 * - :py:class:`pyderasn.VisibleString`
3877 * - :py:class:`pyderasn.ISO646String`
3879 * - :py:class:`pyderasn.GeneralString`
3881 * - :py:class:`pyderasn.UniversalString`
3883 * - :py:class:`pyderasn.BMPString`
3888 def _value_sanitize(self, value):
3890 value_decoded = None
3891 if isinstance(value, self.__class__):
3892 value_raw = value._value
3893 elif isinstance(value, text_type):
3894 value_decoded = value
3895 elif isinstance(value, binary_type):
3898 raise InvalidValueType((self.__class__, text_type, binary_type))
3901 value_decoded.encode(self.encoding)
3902 if value_raw is None else value_raw
3905 value_raw.decode(self.encoding)
3906 if value_decoded is None else value_decoded
3908 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3909 raise DecodeError(str(err))
3910 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3918 def __eq__(self, their):
3919 if isinstance(their, binary_type):
3920 return self._value == their
3921 if isinstance(their, text_type):
3922 return self._value == their.encode(self.encoding)
3923 if not isinstance(their, self.__class__):
3926 self._value == their._value and
3927 self.tag == their.tag and
3928 self._expl == their._expl
3931 def __unicode__(self):
3933 return self._value.decode(self.encoding)
3934 return text_type(self._value)
3937 return pp_console_row(next(self.pps(no_unicode=PY2)))
3939 def pps(self, decode_path=(), no_unicode=False):
3943 hexenc(bytes(self)) if no_unicode else
3944 "".join(escape_control_unicode(c) for c in self.__unicode__())
3948 asn1_type_name=self.asn1_type_name,
3949 obj_name=self.__class__.__name__,
3950 decode_path=decode_path,
3952 optional=self.optional,
3953 default=self == self.default,
3954 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3955 expl=None if self._expl is None else tag_decode(self._expl),
3960 expl_offset=self.expl_offset if self.expled else None,
3961 expl_tlen=self.expl_tlen if self.expled else None,
3962 expl_llen=self.expl_llen if self.expled else None,
3963 expl_vlen=self.expl_vlen if self.expled else None,
3964 expl_lenindef=self.expl_lenindef,
3965 ber_encoded=self.ber_encoded,
3968 for pp in self.pps_lenindef(decode_path):
3972 class UTF8String(CommonString):
3974 tag_default = tag_encode(12)
3976 asn1_type_name = "UTF8String"
3979 class AllowableCharsMixin(object):
3981 def allowable_chars(self):
3983 return self._allowable_chars
3984 return frozenset(six_unichr(c) for c in self._allowable_chars)
3987 class NumericString(AllowableCharsMixin, CommonString):
3990 Its value is properly sanitized: only ASCII digits with spaces can
3993 >>> NumericString().allowable_chars
3994 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3997 tag_default = tag_encode(18)
3999 asn1_type_name = "NumericString"
4000 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
4002 def _value_sanitize(self, value):
4003 value = super(NumericString, self)._value_sanitize(value)
4004 if not frozenset(value) <= self._allowable_chars:
4005 raise DecodeError("non-numeric value")
4009 PrintableStringState = namedtuple(
4010 "PrintableStringState",
4011 OctetStringState._fields + ("allowable_chars",),
4015 class PrintableString(AllowableCharsMixin, CommonString):
4018 Its value is properly sanitized: see X.680 41.4 table 10.
4020 >>> PrintableString().allowable_chars
4021 frozenset([' ', "'", ..., 'z'])
4022 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4023 PrintableString PrintableString foo*bar
4024 >>> obj.allow_asterisk, obj.allow_ampersand
4028 tag_default = tag_encode(19)
4030 asn1_type_name = "PrintableString"
4031 _allowable_chars = frozenset(
4032 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4034 _asterisk = frozenset("*".encode("ascii"))
4035 _ampersand = frozenset("&".encode("ascii"))
4047 allow_asterisk=False,
4048 allow_ampersand=False,
4051 :param allow_asterisk: allow asterisk character
4052 :param allow_ampersand: allow ampersand character
4055 self._allowable_chars |= self._asterisk
4057 self._allowable_chars |= self._ampersand
4058 super(PrintableString, self).__init__(
4059 value, bounds, impl, expl, default, optional, _decoded, ctx,
4063 def allow_asterisk(self):
4064 """Is asterisk character allowed?
4066 return self._asterisk <= self._allowable_chars
4069 def allow_ampersand(self):
4070 """Is ampersand character allowed?
4072 return self._ampersand <= self._allowable_chars
4074 def _value_sanitize(self, value):
4075 value = super(PrintableString, self)._value_sanitize(value)
4076 if not frozenset(value) <= self._allowable_chars:
4077 raise DecodeError("non-printable value")
4080 def __getstate__(self):
4081 return PrintableStringState(
4082 *super(PrintableString, self).__getstate__(),
4083 **{"allowable_chars": self._allowable_chars}
4086 def __setstate__(self, state):
4087 super(PrintableString, self).__setstate__(state)
4088 self._allowable_chars = state.allowable_chars
4099 return self.__class__(
4102 (self._bound_min, self._bound_max)
4103 if bounds is None else bounds
4105 impl=self.tag if impl is None else impl,
4106 expl=self._expl if expl is None else expl,
4107 default=self.default if default is None else default,
4108 optional=self.optional if optional is None else optional,
4109 allow_asterisk=self.allow_asterisk,
4110 allow_ampersand=self.allow_ampersand,
4114 class TeletexString(CommonString):
4116 tag_default = tag_encode(20)
4118 asn1_type_name = "TeletexString"
4121 class T61String(TeletexString):
4123 asn1_type_name = "T61String"
4126 class VideotexString(CommonString):
4128 tag_default = tag_encode(21)
4129 encoding = "iso-8859-1"
4130 asn1_type_name = "VideotexString"
4133 class IA5String(CommonString):
4135 tag_default = tag_encode(22)
4137 asn1_type_name = "IA5"
4140 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4141 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4142 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4145 def fractions2float(fractions_raw):
4146 pureint(fractions_raw)
4147 return float("0." + fractions_raw)
4150 class VisibleString(CommonString):
4152 tag_default = tag_encode(26)
4154 asn1_type_name = "VisibleString"
4157 UTCTimeState = namedtuple("UTCTimeState", OctetStringState._fields + ("ber_raw",))
4160 class UTCTime(VisibleString):
4161 """``UTCTime`` datetime type
4163 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4164 UTCTime UTCTime 2017-09-30T22:07:50
4170 datetime.datetime(2017, 9, 30, 22, 7, 50)
4171 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4172 datetime.datetime(1957, 9, 30, 22, 7, 50)
4176 Pay attention that UTCTime can not hold full year, so all years
4177 having < 50 years are treated as 20xx, 19xx otherwise, according
4178 to X.509 recommendation.
4182 No strict validation of UTC offsets are made, but very crude:
4184 * minutes are not exceeding 60
4185 * offset value is not exceeding 14 hours
4187 __slots__ = ("_ber_raw",)
4188 tag_default = tag_encode(23)
4190 asn1_type_name = "UTCTime"
4200 bounds=None, # dummy argument, workability for OctetString.decode
4204 :param value: set the value. Either datetime type, or
4205 :py:class:`pyderasn.UTCTime` object
4206 :param bytes impl: override default tag with ``IMPLICIT`` one
4207 :param bytes expl: override default tag with ``EXPLICIT`` one
4208 :param default: set default value. Type same as in ``value``
4209 :param bool optional: is object ``OPTIONAL`` in sequence
4211 super(UTCTime, self).__init__(
4212 None, None, impl, expl, None, optional, _decoded, ctx,
4215 self._ber_raw = None
4216 if value is not None:
4217 self._value, self._ber_raw = self._value_sanitize(value, ctx)
4218 self.ber_encoded = self._ber_raw is not None
4219 if default is not None:
4220 default, _ = self._value_sanitize(default)
4221 self.default = self.__class__(
4226 if self._value is None:
4227 self._value = default
4229 self.optional = optional
4231 def _strptime_bered(self, value):
4232 year = pureint(value[:2])
4233 year += 2000 if year < 50 else 1900
4236 pureint(value[2:4]), # %m
4237 pureint(value[4:6]), # %d
4238 pureint(value[6:8]), # %H
4239 pureint(value[8:10]), # %M
4243 raise ValueError("no timezone")
4245 if value[-1] == "Z":
4249 raise ValueError("invalid UTC offset")
4250 if value[-5] == "-":
4252 elif value[-5] == "+":
4255 raise ValueError("invalid UTC offset")
4256 offset = 60 * pureint(value[-2:])
4258 raise ValueError("invalid UTC offset minutes")
4259 offset += 3600 * pureint(value[-4:-2])
4260 if offset > 14 * 3600:
4261 raise ValueError("too big UTC offset")
4265 return offset, decoded
4267 raise ValueError("invalid UTC offset seconds")
4268 seconds = pureint(value)
4270 raise ValueError("invalid seconds value")
4271 decoded += timedelta(seconds=seconds)
4272 return offset, decoded
4274 def _strptime(self, value):
4275 # datetime.strptime's format: %y%m%d%H%M%SZ
4276 if len(value) != LEN_YYMMDDHHMMSSZ:
4277 raise ValueError("invalid UTCTime length")
4278 if value[-1] != "Z":
4279 raise ValueError("non UTC timezone")
4280 year = pureint(value[:2])
4281 year += 2000 if year < 50 else 1900
4284 pureint(value[2:4]), # %m
4285 pureint(value[4:6]), # %d
4286 pureint(value[6:8]), # %H
4287 pureint(value[8:10]), # %M
4288 pureint(value[10:12]), # %S
4291 def _dt_sanitize(self, value):
4292 if value.year < 1950 or value.year > 2049:
4293 raise ValueError("UTCTime can hold only 1950-2049 years")
4294 return value.replace(microsecond=0)
4296 def _value_sanitize(self, value, ctx=None):
4297 if isinstance(value, binary_type):
4299 value_decoded = value.decode("ascii")
4300 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4301 raise DecodeError("invalid UTCTime encoding: %r" % err)
4304 return self._strptime(value_decoded), None
4305 except (TypeError, ValueError) as _err:
4307 if (ctx is not None) and ctx.get("bered", False):
4309 offset, _value = self._strptime_bered(value_decoded)
4310 _value = _value - timedelta(seconds=offset)
4311 return self._dt_sanitize(_value), value_decoded
4312 except (TypeError, ValueError, OverflowError) as _err:
4315 "invalid %s format: %r" % (self.asn1_type_name, err),
4316 klass=self.__class__,
4318 if isinstance(value, self.__class__):
4319 return value._value, None
4320 if isinstance(value, datetime):
4321 return self._dt_sanitize(value), None
4322 raise InvalidValueType((self.__class__, datetime))
4324 def _pp_value(self):
4326 value = self._value.isoformat()
4327 if self.ber_encoded:
4328 value += " (%s)" % self._ber_raw
4331 def __unicode__(self):
4333 value = self._value.isoformat()
4334 if self.ber_encoded:
4335 value += " (%s)" % self._ber_raw
4337 return text_type(self._pp_value())
4339 def __getstate__(self):
4340 return UTCTimeState(
4341 *super(UTCTime, self).__getstate__(),
4342 **{"ber_raw": self._ber_raw}
4345 def __setstate__(self, state):
4346 super(UTCTime, self).__setstate__(state)
4347 self._ber_raw = state.ber_raw
4349 def __bytes__(self):
4350 self._assert_ready()
4351 return self._encode_time()
4353 def __eq__(self, their):
4354 if isinstance(their, binary_type):
4355 return self._encode_time() == their
4356 if isinstance(their, datetime):
4357 return self.todatetime() == their
4358 if not isinstance(their, self.__class__):
4361 self._value == their._value and
4362 self.tag == their.tag and
4363 self._expl == their._expl
4366 def _encode_time(self):
4367 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4370 self._assert_ready()
4371 value = self._encode_time()
4372 return b"".join((self.tag, len_encode(len(value)), value))
4374 def todatetime(self):
4378 return pp_console_row(next(self.pps()))
4380 def pps(self, decode_path=()):
4383 asn1_type_name=self.asn1_type_name,
4384 obj_name=self.__class__.__name__,
4385 decode_path=decode_path,
4386 value=self._pp_value(),
4387 optional=self.optional,
4388 default=self == self.default,
4389 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4390 expl=None if self._expl is None else tag_decode(self._expl),
4395 expl_offset=self.expl_offset if self.expled else None,
4396 expl_tlen=self.expl_tlen if self.expled else None,
4397 expl_llen=self.expl_llen if self.expled else None,
4398 expl_vlen=self.expl_vlen if self.expled else None,
4399 expl_lenindef=self.expl_lenindef,
4400 ber_encoded=self.ber_encoded,
4403 for pp in self.pps_lenindef(decode_path):
4407 class GeneralizedTime(UTCTime):
4408 """``GeneralizedTime`` datetime type
4410 This type is similar to :py:class:`pyderasn.UTCTime`.
4412 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4413 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4415 '20170930220750.000123Z'
4416 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4417 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4421 Only microsecond fractions are supported in DER encoding.
4422 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4423 higher precision values.
4427 BER encoded data can loss information (accuracy) during decoding
4428 because of float transformations.
4432 Local times (without explicit timezone specification) are treated
4433 as UTC one, no transformations are made.
4437 Zero year is unsupported.
4440 tag_default = tag_encode(24)
4441 asn1_type_name = "GeneralizedTime"
4443 def _dt_sanitize(self, value):
4446 def _strptime_bered(self, value):
4447 if len(value) < 4 + 3 * 2:
4448 raise ValueError("invalid GeneralizedTime")
4450 pureint(value[:4]), # %Y
4451 pureint(value[4:6]), # %m
4452 pureint(value[6:8]), # %d
4453 pureint(value[8:10]), # %H
4458 return offset, decoded
4459 if value[-1] == "Z":
4462 for char, sign in (("-", -1), ("+", 1)):
4463 idx = value.rfind(char)
4466 offset_raw = value[idx + 1:].replace(":", "")
4467 if len(offset_raw) not in (2, 4):
4468 raise ValueError("invalid UTC offset")
4470 offset = 60 * pureint(offset_raw[2:] or "0")
4472 raise ValueError("invalid UTC offset minutes")
4473 offset += 3600 * pureint(offset_raw[:2])
4474 if offset > 14 * 3600:
4475 raise ValueError("too big UTC offset")
4479 return offset, decoded
4480 decimal_signs = ".,"
4481 if value[0] in decimal_signs:
4483 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4486 raise ValueError("stripped minutes")
4487 decoded += timedelta(seconds=60 * pureint(value[:2]))
4490 return offset, decoded
4491 if value[0] in decimal_signs:
4493 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4496 raise ValueError("stripped seconds")
4497 decoded += timedelta(seconds=pureint(value[:2]))
4500 return offset, decoded
4501 if value[0] not in decimal_signs:
4502 raise ValueError("invalid format after seconds")
4504 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4507 def _strptime(self, value):
4509 if l == LEN_YYYYMMDDHHMMSSZ:
4510 # datetime.strptime's format: %Y%m%d%H%M%SZ
4511 if value[-1] != "Z":
4512 raise ValueError("non UTC timezone")
4514 pureint(value[:4]), # %Y
4515 pureint(value[4:6]), # %m
4516 pureint(value[6:8]), # %d
4517 pureint(value[8:10]), # %H
4518 pureint(value[10:12]), # %M
4519 pureint(value[12:14]), # %S
4521 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4522 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4523 if value[-1] != "Z":
4524 raise ValueError("non UTC timezone")
4525 if value[14] != ".":
4526 raise ValueError("no fractions separator")
4529 raise ValueError("trailing zero")
4532 raise ValueError("only microsecond fractions are supported")
4533 us = pureint(us + ("0" * (6 - us_len)))
4535 pureint(value[:4]), # %Y
4536 pureint(value[4:6]), # %m
4537 pureint(value[6:8]), # %d
4538 pureint(value[8:10]), # %H
4539 pureint(value[10:12]), # %M
4540 pureint(value[12:14]), # %S
4544 raise ValueError("invalid GeneralizedTime length")
4546 def _encode_time(self):
4548 encoded = value.strftime("%Y%m%d%H%M%S")
4549 if value.microsecond > 0:
4550 encoded += (".%06d" % value.microsecond).rstrip("0")
4551 return (encoded + "Z").encode("ascii")
4554 class GraphicString(CommonString):
4556 tag_default = tag_encode(25)
4557 encoding = "iso-8859-1"
4558 asn1_type_name = "GraphicString"
4561 class ISO646String(VisibleString):
4563 asn1_type_name = "ISO646String"
4566 class GeneralString(CommonString):
4568 tag_default = tag_encode(27)
4569 encoding = "iso-8859-1"
4570 asn1_type_name = "GeneralString"
4573 class UniversalString(CommonString):
4575 tag_default = tag_encode(28)
4576 encoding = "utf-32-be"
4577 asn1_type_name = "UniversalString"
4580 class BMPString(CommonString):
4582 tag_default = tag_encode(30)
4583 encoding = "utf-16-be"
4584 asn1_type_name = "BMPString"
4587 ChoiceState = namedtuple("ChoiceState", (
4605 """``CHOICE`` special type
4609 class GeneralName(Choice):
4611 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4612 ("dNSName", IA5String(impl=tag_ctxp(2))),
4615 >>> gn = GeneralName()
4617 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4618 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4619 >>> gn["dNSName"] = IA5String("bar.baz")
4620 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4621 >>> gn["rfc822Name"]
4624 [2] IA5String IA5 bar.baz
4627 >>> gn.value == gn["dNSName"]
4630 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4632 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4633 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4635 __slots__ = ("specs",)
4637 asn1_type_name = "CHOICE"
4650 :param value: set the value. Either ``(choice, value)`` tuple, or
4651 :py:class:`pyderasn.Choice` object
4652 :param bytes impl: can not be set, do **not** use it
4653 :param bytes expl: override default tag with ``EXPLICIT`` one
4654 :param default: set default value. Type same as in ``value``
4655 :param bool optional: is object ``OPTIONAL`` in sequence
4657 if impl is not None:
4658 raise ValueError("no implicit tag allowed for CHOICE")
4659 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4661 schema = getattr(self, "schema", ())
4662 if len(schema) == 0:
4663 raise ValueError("schema must be specified")
4665 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4668 if value is not None:
4669 self._value = self._value_sanitize(value)
4670 if default is not None:
4671 default_value = self._value_sanitize(default)
4672 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4673 default_obj.specs = self.specs
4674 default_obj._value = default_value
4675 self.default = default_obj
4677 self._value = copy(default_obj._value)
4679 def _value_sanitize(self, value):
4680 if isinstance(value, tuple) and len(value) == 2:
4682 spec = self.specs.get(choice)
4684 raise ObjUnknown(choice)
4685 if not isinstance(obj, spec.__class__):
4686 raise InvalidValueType((spec,))
4687 return (choice, spec(obj))
4688 if isinstance(value, self.__class__):
4690 raise InvalidValueType((self.__class__, tuple))
4694 return self._value is not None and self._value[1].ready
4698 return self.expl_lenindef or (
4699 (self._value is not None) and
4700 self._value[1].bered
4703 def __getstate__(self):
4720 def __setstate__(self, state):
4721 super(Choice, self).__setstate__(state)
4722 self.specs = state.specs
4723 self._value = state.value
4724 self._expl = state.expl
4725 self.default = state.default
4726 self.optional = state.optional
4727 self.offset = state.offset
4728 self.llen = state.llen
4729 self.vlen = state.vlen
4730 self.expl_lenindef = state.expl_lenindef
4731 self.lenindef = state.lenindef
4732 self.ber_encoded = state.ber_encoded
4734 def __eq__(self, their):
4735 if isinstance(their, tuple) and len(their) == 2:
4736 return self._value == their
4737 if not isinstance(their, self.__class__):
4740 self.specs == their.specs and
4741 self._value == their._value
4751 return self.__class__(
4754 expl=self._expl if expl is None else expl,
4755 default=self.default if default is None else default,
4756 optional=self.optional if optional is None else optional,
4761 self._assert_ready()
4762 return self._value[0]
4766 self._assert_ready()
4767 return self._value[1]
4769 def __getitem__(self, key):
4770 if key not in self.specs:
4771 raise ObjUnknown(key)
4772 if self._value is None:
4774 choice, value = self._value
4779 def __setitem__(self, key, value):
4780 spec = self.specs.get(key)
4782 raise ObjUnknown(key)
4783 if not isinstance(value, spec.__class__):
4784 raise InvalidValueType((spec.__class__,))
4785 self._value = (key, spec(value))
4793 return self._value[1].decoded if self.ready else False
4796 self._assert_ready()
4797 return self._value[1].encode()
4799 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4800 for choice, spec in iteritems(self.specs):
4801 sub_decode_path = decode_path + (choice,)
4807 decode_path=sub_decode_path,
4810 _ctx_immutable=False,
4817 klass=self.__class__,
4818 decode_path=decode_path,
4821 if tag_only: # pragma: no cover
4823 value, tail = spec.decode(
4827 decode_path=sub_decode_path,
4829 _ctx_immutable=False,
4831 obj = self.__class__(
4834 default=self.default,
4835 optional=self.optional,
4836 _decoded=(offset, 0, value.fulllen),
4838 obj._value = (choice, value)
4842 value = pp_console_row(next(self.pps()))
4844 value = "%s[%r]" % (value, self.value)
4847 def pps(self, decode_path=()):
4850 asn1_type_name=self.asn1_type_name,
4851 obj_name=self.__class__.__name__,
4852 decode_path=decode_path,
4853 value=self.choice if self.ready else None,
4854 optional=self.optional,
4855 default=self == self.default,
4856 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4857 expl=None if self._expl is None else tag_decode(self._expl),
4862 expl_lenindef=self.expl_lenindef,
4866 yield self.value.pps(decode_path=decode_path + (self.choice,))
4867 for pp in self.pps_lenindef(decode_path):
4871 class PrimitiveTypes(Choice):
4872 """Predefined ``CHOICE`` for all generic primitive types
4874 It could be useful for general decoding of some unspecified values:
4876 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4877 OCTET STRING 3 bytes 666f6f
4878 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4882 schema = tuple((klass.__name__, klass()) for klass in (
4906 AnyState = namedtuple("AnyState", (
4923 """``ANY`` special type
4925 >>> Any(Integer(-123))
4927 >>> a = Any(OctetString(b"hello world").encode())
4928 ANY 040b68656c6c6f20776f726c64
4929 >>> hexenc(bytes(a))
4930 b'0x040x0bhello world'
4932 __slots__ = ("defined",)
4933 tag_default = tag_encode(0)
4934 asn1_type_name = "ANY"
4944 :param value: set the value. Either any kind of pyderasn's
4945 **ready** object, or bytes. Pay attention that
4946 **no** validation is performed is raw binary value
4948 :param bytes expl: override default tag with ``EXPLICIT`` one
4949 :param bool optional: is object ``OPTIONAL`` in sequence
4951 super(Any, self).__init__(None, expl, None, optional, _decoded)
4952 self._value = None if value is None else self._value_sanitize(value)
4955 def _value_sanitize(self, value):
4956 if isinstance(value, binary_type):
4958 if isinstance(value, self.__class__):
4960 if isinstance(value, Obj):
4961 return value.encode()
4962 raise InvalidValueType((self.__class__, Obj, binary_type))
4966 return self._value is not None
4970 if self.expl_lenindef or self.lenindef:
4972 if self.defined is None:
4974 return self.defined[1].bered
4976 def __getstate__(self):
4992 def __setstate__(self, state):
4993 super(Any, self).__setstate__(state)
4994 self._value = state.value
4995 self.tag = state.tag
4996 self._expl = state.expl
4997 self.optional = state.optional
4998 self.offset = state.offset
4999 self.llen = state.llen
5000 self.vlen = state.vlen
5001 self.expl_lenindef = state.expl_lenindef
5002 self.lenindef = state.lenindef
5003 self.ber_encoded = state.ber_encoded
5004 self.defined = state.defined
5006 def __eq__(self, their):
5007 if isinstance(their, binary_type):
5008 return self._value == their
5009 if issubclass(their.__class__, Any):
5010 return self._value == their._value
5019 return self.__class__(
5021 expl=self._expl if expl is None else expl,
5022 optional=self.optional if optional is None else optional,
5025 def __bytes__(self):
5026 self._assert_ready()
5034 self._assert_ready()
5037 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5039 t, tlen, lv = tag_strip(tlv)
5040 except DecodeError as err:
5041 raise err.__class__(
5043 klass=self.__class__,
5044 decode_path=decode_path,
5048 l, llen, v = len_decode(lv)
5049 except LenIndefForm as err:
5050 if not ctx.get("bered", False):
5051 raise err.__class__(
5053 klass=self.__class__,
5054 decode_path=decode_path,
5057 llen, vlen, v = 1, 0, lv[1:]
5058 sub_offset = offset + tlen + llen
5060 while v[:EOC_LEN].tobytes() != EOC:
5061 chunk, v = Any().decode(
5064 decode_path=decode_path + (str(chunk_i),),
5067 _ctx_immutable=False,
5069 vlen += chunk.tlvlen
5070 sub_offset += chunk.tlvlen
5072 tlvlen = tlen + llen + vlen + EOC_LEN
5073 obj = self.__class__(
5074 value=tlv[:tlvlen].tobytes(),
5076 optional=self.optional,
5077 _decoded=(offset, 0, tlvlen),
5080 obj.tag = t.tobytes()
5081 return obj, v[EOC_LEN:]
5082 except DecodeError as err:
5083 raise err.__class__(
5085 klass=self.__class__,
5086 decode_path=decode_path,
5090 raise NotEnoughData(
5091 "encoded length is longer than data",
5092 klass=self.__class__,
5093 decode_path=decode_path,
5096 tlvlen = tlen + llen + l
5097 v, tail = tlv[:tlvlen], v[l:]
5098 obj = self.__class__(
5101 optional=self.optional,
5102 _decoded=(offset, 0, tlvlen),
5104 obj.tag = t.tobytes()
5108 return pp_console_row(next(self.pps()))
5110 def pps(self, decode_path=()):
5113 asn1_type_name=self.asn1_type_name,
5114 obj_name=self.__class__.__name__,
5115 decode_path=decode_path,
5116 blob=self._value if self.ready else None,
5117 optional=self.optional,
5118 default=self == self.default,
5119 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5120 expl=None if self._expl is None else tag_decode(self._expl),
5125 expl_offset=self.expl_offset if self.expled else None,
5126 expl_tlen=self.expl_tlen if self.expled else None,
5127 expl_llen=self.expl_llen if self.expled else None,
5128 expl_vlen=self.expl_vlen if self.expled else None,
5129 expl_lenindef=self.expl_lenindef,
5130 lenindef=self.lenindef,
5133 defined_by, defined = self.defined or (None, None)
5134 if defined_by is not None:
5136 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5138 for pp in self.pps_lenindef(decode_path):
5142 ########################################################################
5143 # ASN.1 constructed types
5144 ########################################################################
5146 def get_def_by_path(defines_by_path, sub_decode_path):
5147 """Get define by decode path
5149 for path, define in defines_by_path:
5150 if len(path) != len(sub_decode_path):
5152 for p1, p2 in zip(path, sub_decode_path):
5153 if (p1 != any) and (p1 != p2):
5159 def abs_decode_path(decode_path, rel_path):
5160 """Create an absolute decode path from current and relative ones
5162 :param decode_path: current decode path, starting point. Tuple of strings
5163 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5164 If first tuple's element is "/", then treat it as
5165 an absolute path, ignoring ``decode_path`` as
5166 starting point. Also this tuple can contain ".."
5167 elements, stripping the leading element from
5170 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5171 ("foo", "bar", "baz", "whatever")
5172 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5174 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5177 if rel_path[0] == "/":
5179 if rel_path[0] == "..":
5180 return abs_decode_path(decode_path[:-1], rel_path[1:])
5181 return decode_path + rel_path
5184 SequenceState = namedtuple("SequenceState", (
5201 class Sequence(Obj):
5202 """``SEQUENCE`` structure type
5204 You have to make specification of sequence::
5206 class Extension(Sequence):
5208 ("extnID", ObjectIdentifier()),
5209 ("critical", Boolean(default=False)),
5210 ("extnValue", OctetString()),
5213 Then, you can work with it as with dictionary.
5215 >>> ext = Extension()
5216 >>> Extension().specs
5218 ('extnID', OBJECT IDENTIFIER),
5219 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5220 ('extnValue', OCTET STRING),
5222 >>> ext["extnID"] = "1.2.3"
5223 Traceback (most recent call last):
5224 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5225 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5227 You can determine if sequence is ready to be encoded:
5232 Traceback (most recent call last):
5233 pyderasn.ObjNotReady: object is not ready: extnValue
5234 >>> ext["extnValue"] = OctetString(b"foobar")
5238 Value you want to assign, must have the same **type** as in
5239 corresponding specification, but it can have different tags,
5240 optional/default attributes -- they will be taken from specification
5243 class TBSCertificate(Sequence):
5245 ("version", Version(expl=tag_ctxc(0), default="v1")),
5248 >>> tbs = TBSCertificate()
5249 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5251 Assign ``None`` to remove value from sequence.
5253 You can set values in Sequence during its initialization:
5255 >>> AlgorithmIdentifier((
5256 ("algorithm", ObjectIdentifier("1.2.3")),
5257 ("parameters", Any(Null()))
5259 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5261 You can determine if value exists/set in the sequence and take its value:
5263 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5266 OBJECT IDENTIFIER 1.2.3
5268 But pay attention that if value has default, then it won't be (not
5269 in) in the sequence (because ``DEFAULT`` must not be encoded in
5270 DER), but you can read its value:
5272 >>> "critical" in ext, ext["critical"]
5273 (False, BOOLEAN False)
5274 >>> ext["critical"] = Boolean(True)
5275 >>> "critical" in ext, ext["critical"]
5276 (True, BOOLEAN True)
5278 All defaulted values are always optional.
5280 .. _allow_default_values_ctx:
5282 DER prohibits default value encoding and will raise an error if
5283 default value is unexpectedly met during decode.
5284 If :ref:`bered <bered_ctx>` context option is set, then no error
5285 will be raised, but ``bered`` attribute set. You can disable strict
5286 defaulted values existence validation by setting
5287 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5289 Two sequences are equal if they have equal specification (schema),
5290 implicit/explicit tagging and the same values.
5292 __slots__ = ("specs",)
5293 tag_default = tag_encode(form=TagFormConstructed, num=16)
5294 asn1_type_name = "SEQUENCE"
5306 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5308 schema = getattr(self, "schema", ())
5310 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
5313 if value is not None:
5314 if issubclass(value.__class__, Sequence):
5315 self._value = value._value
5316 elif hasattr(value, "__iter__"):
5317 for seq_key, seq_value in value:
5318 self[seq_key] = seq_value
5320 raise InvalidValueType((Sequence,))
5321 if default is not None:
5322 if not issubclass(default.__class__, Sequence):
5323 raise InvalidValueType((Sequence,))
5324 default_value = default._value
5325 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5326 default_obj.specs = self.specs
5327 default_obj._value = default_value
5328 self.default = default_obj
5330 self._value = copy(default_obj._value)
5334 for name, spec in iteritems(self.specs):
5335 value = self._value.get(name)
5346 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5348 return any(value.bered for value in itervalues(self._value))
5350 def __getstate__(self):
5351 return SequenceState(
5354 {k: copy(v) for k, v in iteritems(self._value)},
5367 def __setstate__(self, state):
5368 super(Sequence, self).__setstate__(state)
5369 self.specs = state.specs
5370 self._value = state.value
5371 self.tag = state.tag
5372 self._expl = state.expl
5373 self.default = state.default
5374 self.optional = state.optional
5375 self.offset = state.offset
5376 self.llen = state.llen
5377 self.vlen = state.vlen
5378 self.expl_lenindef = state.expl_lenindef
5379 self.lenindef = state.lenindef
5380 self.ber_encoded = state.ber_encoded
5382 def __eq__(self, their):
5383 if not isinstance(their, self.__class__):
5386 self.specs == their.specs and
5387 self.tag == their.tag and
5388 self._expl == their._expl and
5389 self._value == their._value
5400 return self.__class__(
5403 impl=self.tag if impl is None else impl,
5404 expl=self._expl if expl is None else expl,
5405 default=self.default if default is None else default,
5406 optional=self.optional if optional is None else optional,
5409 def __contains__(self, key):
5410 return key in self._value
5412 def __setitem__(self, key, value):
5413 spec = self.specs.get(key)
5415 raise ObjUnknown(key)
5417 self._value.pop(key, None)
5419 if not isinstance(value, spec.__class__):
5420 raise InvalidValueType((spec.__class__,))
5421 value = spec(value=value)
5422 if spec.default is not None and value == spec.default:
5423 self._value.pop(key, None)
5425 self._value[key] = value
5427 def __getitem__(self, key):
5428 value = self._value.get(key)
5429 if value is not None:
5431 spec = self.specs.get(key)
5433 raise ObjUnknown(key)
5434 if spec.default is not None:
5438 def _encoded_values(self):
5440 for name, spec in iteritems(self.specs):
5441 value = self._value.get(name)
5445 raise ObjNotReady(name)
5446 raws.append(value.encode())
5450 v = b"".join(self._encoded_values())
5451 return b"".join((self.tag, len_encode(len(v)), v))
5453 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5455 t, tlen, lv = tag_strip(tlv)
5456 except DecodeError as err:
5457 raise err.__class__(
5459 klass=self.__class__,
5460 decode_path=decode_path,
5465 klass=self.__class__,
5466 decode_path=decode_path,
5469 if tag_only: # pragma: no cover
5472 ctx_bered = ctx.get("bered", False)
5474 l, llen, v = len_decode(lv)
5475 except LenIndefForm as err:
5477 raise err.__class__(
5479 klass=self.__class__,
5480 decode_path=decode_path,
5483 l, llen, v = 0, 1, lv[1:]
5485 except DecodeError as err:
5486 raise err.__class__(
5488 klass=self.__class__,
5489 decode_path=decode_path,
5493 raise NotEnoughData(
5494 "encoded length is longer than data",
5495 klass=self.__class__,
5496 decode_path=decode_path,
5500 v, tail = v[:l], v[l:]
5502 sub_offset = offset + tlen + llen
5505 ctx_allow_default_values = ctx.get("allow_default_values", False)
5506 for name, spec in iteritems(self.specs):
5507 if spec.optional and (
5508 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5512 sub_decode_path = decode_path + (name,)
5514 value, v_tail = spec.decode(
5518 decode_path=sub_decode_path,
5520 _ctx_immutable=False,
5522 except TagMismatch as err:
5523 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5527 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5528 if defined is not None:
5529 defined_by, defined_spec = defined
5530 if issubclass(value.__class__, SequenceOf):
5531 for i, _value in enumerate(value):
5532 sub_sub_decode_path = sub_decode_path + (
5534 DecodePathDefBy(defined_by),
5536 defined_value, defined_tail = defined_spec.decode(
5537 memoryview(bytes(_value)),
5539 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5540 if value.expled else (value.tlen + value.llen)
5543 decode_path=sub_sub_decode_path,
5545 _ctx_immutable=False,
5547 if len(defined_tail) > 0:
5550 klass=self.__class__,
5551 decode_path=sub_sub_decode_path,
5554 _value.defined = (defined_by, defined_value)
5556 defined_value, defined_tail = defined_spec.decode(
5557 memoryview(bytes(value)),
5559 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5560 if value.expled else (value.tlen + value.llen)
5563 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5565 _ctx_immutable=False,
5567 if len(defined_tail) > 0:
5570 klass=self.__class__,
5571 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5574 value.defined = (defined_by, defined_value)
5576 value_len = value.fulllen
5578 sub_offset += value_len
5580 if spec.default is not None and value == spec.default:
5581 if ctx_bered or ctx_allow_default_values:
5585 "DEFAULT value met",
5586 klass=self.__class__,
5587 decode_path=sub_decode_path,
5590 values[name] = value
5592 spec_defines = getattr(spec, "defines", ())
5593 if len(spec_defines) == 0:
5594 defines_by_path = ctx.get("defines_by_path", ())
5595 if len(defines_by_path) > 0:
5596 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5597 if spec_defines is not None and len(spec_defines) > 0:
5598 for rel_path, schema in spec_defines:
5599 defined = schema.get(value, None)
5600 if defined is not None:
5601 ctx.setdefault("_defines", []).append((
5602 abs_decode_path(sub_decode_path[:-1], rel_path),
5606 if v[:EOC_LEN].tobytes() != EOC:
5609 klass=self.__class__,
5610 decode_path=decode_path,
5618 klass=self.__class__,
5619 decode_path=decode_path,
5622 obj = self.__class__(
5626 default=self.default,
5627 optional=self.optional,
5628 _decoded=(offset, llen, vlen),
5631 obj.lenindef = lenindef
5632 obj.ber_encoded = ber_encoded
5636 value = pp_console_row(next(self.pps()))
5638 for name in self.specs:
5639 _value = self._value.get(name)
5642 cols.append("%s: %s" % (name, repr(_value)))
5643 return "%s[%s]" % (value, "; ".join(cols))
5645 def pps(self, decode_path=()):
5648 asn1_type_name=self.asn1_type_name,
5649 obj_name=self.__class__.__name__,
5650 decode_path=decode_path,
5651 optional=self.optional,
5652 default=self == self.default,
5653 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5654 expl=None if self._expl is None else tag_decode(self._expl),
5659 expl_offset=self.expl_offset if self.expled else None,
5660 expl_tlen=self.expl_tlen if self.expled else None,
5661 expl_llen=self.expl_llen if self.expled else None,
5662 expl_vlen=self.expl_vlen if self.expled else None,
5663 expl_lenindef=self.expl_lenindef,
5664 lenindef=self.lenindef,
5665 ber_encoded=self.ber_encoded,
5668 for name in self.specs:
5669 value = self._value.get(name)
5672 yield value.pps(decode_path=decode_path + (name,))
5673 for pp in self.pps_lenindef(decode_path):
5677 class Set(Sequence):
5678 """``SET`` structure type
5680 Its usage is identical to :py:class:`pyderasn.Sequence`.
5682 .. _allow_unordered_set_ctx:
5684 DER prohibits unordered values encoding and will raise an error
5685 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5686 then no error will occure. Also you can disable strict values
5687 ordering check by setting ``"allow_unordered_set": True``
5688 :ref:`context <ctx>` option.
5691 tag_default = tag_encode(form=TagFormConstructed, num=17)
5692 asn1_type_name = "SET"
5695 raws = self._encoded_values()
5698 return b"".join((self.tag, len_encode(len(v)), v))
5700 def _specs_items(self):
5701 return iteritems(self.specs)
5703 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5705 t, tlen, lv = tag_strip(tlv)
5706 except DecodeError as err:
5707 raise err.__class__(
5709 klass=self.__class__,
5710 decode_path=decode_path,
5715 klass=self.__class__,
5716 decode_path=decode_path,
5722 ctx_bered = ctx.get("bered", False)
5724 l, llen, v = len_decode(lv)
5725 except LenIndefForm as err:
5727 raise err.__class__(
5729 klass=self.__class__,
5730 decode_path=decode_path,
5733 l, llen, v = 0, 1, lv[1:]
5735 except DecodeError as err:
5736 raise err.__class__(
5738 klass=self.__class__,
5739 decode_path=decode_path,
5743 raise NotEnoughData(
5744 "encoded length is longer than data",
5745 klass=self.__class__,
5749 v, tail = v[:l], v[l:]
5751 sub_offset = offset + tlen + llen
5754 ctx_allow_default_values = ctx.get("allow_default_values", False)
5755 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5756 value_prev = memoryview(v[:0])
5759 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5761 for name, spec in self._specs_items():
5762 sub_decode_path = decode_path + (name,)
5768 decode_path=sub_decode_path,
5771 _ctx_immutable=False,
5778 klass=self.__class__,
5779 decode_path=decode_path,
5782 value, v_tail = spec.decode(
5786 decode_path=sub_decode_path,
5788 _ctx_immutable=False,
5790 value_len = value.fulllen
5791 if value_prev.tobytes() > v[:value_len].tobytes():
5792 if ctx_bered or ctx_allow_unordered_set:
5796 "unordered " + self.asn1_type_name,
5797 klass=self.__class__,
5798 decode_path=sub_decode_path,
5801 if spec.default is None or value != spec.default:
5803 elif ctx_bered or ctx_allow_default_values:
5807 "DEFAULT value met",
5808 klass=self.__class__,
5809 decode_path=sub_decode_path,
5812 values[name] = value
5813 value_prev = v[:value_len]
5814 sub_offset += value_len
5817 obj = self.__class__(
5821 default=self.default,
5822 optional=self.optional,
5823 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5826 if v[:EOC_LEN].tobytes() != EOC:
5829 klass=self.__class__,
5830 decode_path=decode_path,
5838 "not all values are ready",
5839 klass=self.__class__,
5840 decode_path=decode_path,
5843 obj.ber_encoded = ber_encoded
5847 SequenceOfState = namedtuple("SequenceOfState", (
5866 class SequenceOf(Obj):
5867 """``SEQUENCE OF`` sequence type
5869 For that kind of type you must specify the object it will carry on
5870 (bounds are for example here, not required)::
5872 class Ints(SequenceOf):
5877 >>> ints.append(Integer(123))
5878 >>> ints.append(Integer(234))
5880 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5881 >>> [int(i) for i in ints]
5883 >>> ints.append(Integer(345))
5884 Traceback (most recent call last):
5885 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5888 >>> ints[1] = Integer(345)
5890 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5892 Also you can initialize sequence with preinitialized values:
5894 >>> ints = Ints([Integer(123), Integer(234)])
5896 __slots__ = ("spec", "_bound_min", "_bound_max")
5897 tag_default = tag_encode(form=TagFormConstructed, num=16)
5898 asn1_type_name = "SEQUENCE OF"
5911 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5913 schema = getattr(self, "schema", None)
5915 raise ValueError("schema must be specified")
5917 self._bound_min, self._bound_max = getattr(
5921 ) if bounds is None else bounds
5923 if value is not None:
5924 self._value = self._value_sanitize(value)
5925 if default is not None:
5926 default_value = self._value_sanitize(default)
5927 default_obj = self.__class__(
5932 default_obj._value = default_value
5933 self.default = default_obj
5935 self._value = copy(default_obj._value)
5937 def _value_sanitize(self, value):
5938 if issubclass(value.__class__, SequenceOf):
5939 value = value._value
5940 elif hasattr(value, "__iter__"):
5943 raise InvalidValueType((self.__class__, iter))
5944 if not self._bound_min <= len(value) <= self._bound_max:
5945 raise BoundsError(self._bound_min, len(value), self._bound_max)
5947 if not isinstance(v, self.spec.__class__):
5948 raise InvalidValueType((self.spec.__class__,))
5953 return all(v.ready for v in self._value)
5957 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5959 return any(v.bered for v in self._value)
5961 def __getstate__(self):
5962 return SequenceOfState(
5965 [copy(v) for v in self._value],
5980 def __setstate__(self, state):
5981 super(SequenceOf, self).__setstate__(state)
5982 self.spec = state.spec
5983 self._value = state.value
5984 self._bound_min = state.bound_min
5985 self._bound_max = state.bound_max
5986 self.tag = state.tag
5987 self._expl = state.expl
5988 self.default = state.default
5989 self.optional = state.optional
5990 self.offset = state.offset
5991 self.llen = state.llen
5992 self.vlen = state.vlen
5993 self.expl_lenindef = state.expl_lenindef
5994 self.lenindef = state.lenindef
5995 self.ber_encoded = state.ber_encoded
5997 def __eq__(self, their):
5998 if isinstance(their, self.__class__):
6000 self.spec == their.spec and
6001 self.tag == their.tag and
6002 self._expl == their._expl and
6003 self._value == their._value
6005 if hasattr(their, "__iter__"):
6006 return self._value == list(their)
6018 return self.__class__(
6022 (self._bound_min, self._bound_max)
6023 if bounds is None else bounds
6025 impl=self.tag if impl is None else impl,
6026 expl=self._expl if expl is None else expl,
6027 default=self.default if default is None else default,
6028 optional=self.optional if optional is None else optional,
6031 def __contains__(self, key):
6032 return key in self._value
6034 def append(self, value):
6035 if not isinstance(value, self.spec.__class__):
6036 raise InvalidValueType((self.spec.__class__,))
6037 if len(self._value) + 1 > self._bound_max:
6040 len(self._value) + 1,
6043 self._value.append(value)
6046 self._assert_ready()
6047 return iter(self._value)
6050 self._assert_ready()
6051 return len(self._value)
6053 def __setitem__(self, key, value):
6054 if not isinstance(value, self.spec.__class__):
6055 raise InvalidValueType((self.spec.__class__,))
6056 self._value[key] = self.spec(value=value)
6058 def __getitem__(self, key):
6059 return self._value[key]
6061 def _encoded_values(self):
6062 return [v.encode() for v in self._value]
6065 v = b"".join(self._encoded_values())
6066 return b"".join((self.tag, len_encode(len(v)), v))
6068 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
6070 t, tlen, lv = tag_strip(tlv)
6071 except DecodeError as err:
6072 raise err.__class__(
6074 klass=self.__class__,
6075 decode_path=decode_path,
6080 klass=self.__class__,
6081 decode_path=decode_path,
6087 ctx_bered = ctx.get("bered", False)
6089 l, llen, v = len_decode(lv)
6090 except LenIndefForm as err:
6092 raise err.__class__(
6094 klass=self.__class__,
6095 decode_path=decode_path,
6098 l, llen, v = 0, 1, lv[1:]
6100 except DecodeError as err:
6101 raise err.__class__(
6103 klass=self.__class__,
6104 decode_path=decode_path,
6108 raise NotEnoughData(
6109 "encoded length is longer than data",
6110 klass=self.__class__,
6111 decode_path=decode_path,
6115 v, tail = v[:l], v[l:]
6117 sub_offset = offset + tlen + llen
6119 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6120 value_prev = memoryview(v[:0])
6124 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6126 sub_decode_path = decode_path + (str(len(_value)),)
6127 value, v_tail = spec.decode(
6131 decode_path=sub_decode_path,
6133 _ctx_immutable=False,
6135 value_len = value.fulllen
6137 if value_prev.tobytes() > v[:value_len].tobytes():
6138 if ctx_bered or ctx_allow_unordered_set:
6142 "unordered " + self.asn1_type_name,
6143 klass=self.__class__,
6144 decode_path=sub_decode_path,
6147 value_prev = v[:value_len]
6148 _value.append(value)
6149 sub_offset += value_len
6153 obj = self.__class__(
6156 bounds=(self._bound_min, self._bound_max),
6159 default=self.default,
6160 optional=self.optional,
6161 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6163 except BoundsError as err:
6166 klass=self.__class__,
6167 decode_path=decode_path,
6171 if v[:EOC_LEN].tobytes() != EOC:
6174 klass=self.__class__,
6175 decode_path=decode_path,
6180 obj.ber_encoded = ber_encoded
6185 pp_console_row(next(self.pps())),
6186 ", ".join(repr(v) for v in self._value),
6189 def pps(self, decode_path=()):
6192 asn1_type_name=self.asn1_type_name,
6193 obj_name=self.__class__.__name__,
6194 decode_path=decode_path,
6195 optional=self.optional,
6196 default=self == self.default,
6197 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6198 expl=None if self._expl is None else tag_decode(self._expl),
6203 expl_offset=self.expl_offset if self.expled else None,
6204 expl_tlen=self.expl_tlen if self.expled else None,
6205 expl_llen=self.expl_llen if self.expled else None,
6206 expl_vlen=self.expl_vlen if self.expled else None,
6207 expl_lenindef=self.expl_lenindef,
6208 lenindef=self.lenindef,
6209 ber_encoded=self.ber_encoded,
6212 for i, value in enumerate(self._value):
6213 yield value.pps(decode_path=decode_path + (str(i),))
6214 for pp in self.pps_lenindef(decode_path):
6218 class SetOf(SequenceOf):
6219 """``SET OF`` sequence type
6221 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6224 tag_default = tag_encode(form=TagFormConstructed, num=17)
6225 asn1_type_name = "SET OF"
6228 raws = self._encoded_values()
6231 return b"".join((self.tag, len_encode(len(v)), v))
6233 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6234 return super(SetOf, self)._decode(
6240 ordering_check=True,
6244 def obj_by_path(pypath): # pragma: no cover
6245 """Import object specified as string Python path
6247 Modules must be separated from classes/functions with ``:``.
6249 >>> obj_by_path("foo.bar:Baz")
6250 <class 'foo.bar.Baz'>
6251 >>> obj_by_path("foo.bar:Baz.boo")
6252 <classmethod 'foo.bar.Baz.boo'>
6254 mod, objs = pypath.rsplit(":", 1)
6255 from importlib import import_module
6256 obj = import_module(mod)
6257 for obj_name in objs.split("."):
6258 obj = getattr(obj, obj_name)
6262 def generic_decoder(): # pragma: no cover
6263 # All of this below is a big hack with self references
6264 choice = PrimitiveTypes()
6265 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6266 choice.specs["SetOf"] = SetOf(schema=choice)
6267 for i in six_xrange(31):
6268 choice.specs["SequenceOf%d" % i] = SequenceOf(
6272 choice.specs["Any"] = Any()
6274 # Class name equals to type name, to omit it from output
6275 class SEQUENCEOF(SequenceOf):
6283 with_decode_path=False,
6284 decode_path_only=(),
6286 def _pprint_pps(pps):
6288 if hasattr(pp, "_fields"):
6290 decode_path_only != () and
6291 pp.decode_path[:len(decode_path_only)] != decode_path_only
6294 if pp.asn1_type_name == Choice.asn1_type_name:
6296 pp_kwargs = pp._asdict()
6297 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6298 pp = _pp(**pp_kwargs)
6299 yield pp_console_row(
6304 with_colours=with_colours,
6305 with_decode_path=with_decode_path,
6306 decode_path_len_decrease=len(decode_path_only),
6308 for row in pp_console_blob(
6310 decode_path_len_decrease=len(decode_path_only),
6314 for row in _pprint_pps(pp):
6316 return "\n".join(_pprint_pps(obj.pps()))
6317 return SEQUENCEOF(), pprint_any
6320 def main(): # pragma: no cover
6322 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6323 parser.add_argument(
6327 help="Skip that number of bytes from the beginning",
6329 parser.add_argument(
6331 help="Python paths to dictionary with OIDs, comma separated",
6333 parser.add_argument(
6335 help="Python path to schema definition to use",
6337 parser.add_argument(
6338 "--defines-by-path",
6339 help="Python path to decoder's defines_by_path",
6341 parser.add_argument(
6343 action="store_true",
6344 help="Disallow BER encoding",
6346 parser.add_argument(
6347 "--print-decode-path",
6348 action="store_true",
6349 help="Print decode paths",
6351 parser.add_argument(
6352 "--decode-path-only",
6353 help="Print only specified decode path",
6355 parser.add_argument(
6357 action="store_true",
6358 help="Allow explicit tag out-of-bound",
6360 parser.add_argument(
6362 type=argparse.FileType("rb"),
6363 help="Path to DER file you want to decode",
6365 args = parser.parse_args()
6366 args.DERFile.seek(args.skip)
6367 der = memoryview(args.DERFile.read())
6368 args.DERFile.close()
6370 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6371 if args.oids else ()
6374 schema = obj_by_path(args.schema)
6375 from functools import partial
6376 pprinter = partial(pprint, big_blobs=True)
6378 schema, pprinter = generic_decoder()
6380 "bered": not args.nobered,
6381 "allow_expl_oob": args.allow_expl_oob,
6383 if args.defines_by_path is not None:
6384 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6385 obj, tail = schema().decode(der, ctx=ctx)
6389 with_colours=environ.get("NO_COLOR") is None,
6390 with_decode_path=args.print_decode_path,
6392 () if args.decode_path_only is None else
6393 tuple(args.decode_path_only.split(":"))
6397 print("\nTrailing data: %s" % hexenc(tail))
6400 if __name__ == "__main__":