3 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
4 # Copyright (C) 2017-2018 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, either version 3 of the
9 # License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this program. If not, see
18 # <http://www.gnu.org/licenses/>.
19 """Python ASN.1 DER/BER codec with abstract structures
21 This library allows you to marshal various structures in ASN.1 DER
22 format, unmarshal them in BER/CER/DER ones.
26 >>> Integer().decode(raw) == i
29 There are primitive types, holding single values
30 (:py:class:`pyderasn.BitString`,
31 :py:class:`pyderasn.Boolean`,
32 :py:class:`pyderasn.Enumerated`,
33 :py:class:`pyderasn.GeneralizedTime`,
34 :py:class:`pyderasn.Integer`,
35 :py:class:`pyderasn.Null`,
36 :py:class:`pyderasn.ObjectIdentifier`,
37 :py:class:`pyderasn.OctetString`,
38 :py:class:`pyderasn.UTCTime`,
39 :py:class:`various strings <pyderasn.CommonString>`
40 (:py:class:`pyderasn.BMPString`,
41 :py:class:`pyderasn.GeneralString`,
42 :py:class:`pyderasn.GraphicString`,
43 :py:class:`pyderasn.IA5String`,
44 :py:class:`pyderasn.ISO646String`,
45 :py:class:`pyderasn.NumericString`,
46 :py:class:`pyderasn.PrintableString`,
47 :py:class:`pyderasn.T61String`,
48 :py:class:`pyderasn.TeletexString`,
49 :py:class:`pyderasn.UniversalString`,
50 :py:class:`pyderasn.UTF8String`,
51 :py:class:`pyderasn.VideotexString`,
52 :py:class:`pyderasn.VisibleString`)),
53 constructed types, holding multiple primitive types
54 (:py:class:`pyderasn.Sequence`,
55 :py:class:`pyderasn.SequenceOf`,
56 :py:class:`pyderasn.Set`,
57 :py:class:`pyderasn.SetOf`),
58 and special types like
59 :py:class:`pyderasn.Any` and
60 :py:class:`pyderasn.Choice`.
68 Most types in ASN.1 has specific tag for them. ``Obj.tag_default`` is
69 the default tag used during coding process. You can override it with
70 either ``IMPLICIT`` (using ``impl`` keyword argument), or
71 ``EXPLICIT`` one (using ``expl`` keyword argument). Both arguments take
72 raw binary string, containing that tag. You can **not** set implicit and
73 explicit tags simultaneously.
75 There are :py:func:`pyderasn.tag_ctxp` and :py:func:`pyderasn.tag_ctxc`
76 functions, allowing you to easily create ``CONTEXT``
77 ``PRIMITIVE``/``CONSTRUCTED`` tags, by specifying only the required tag
78 number. Pay attention that explicit tags always have *constructed* tag
79 (``tag_ctxc``), but implicit tags for primitive types are primitive
84 >>> Integer(impl=tag_ctxp(1))
86 >>> Integer(expl=tag_ctxc(2))
89 Implicit tag is not explicitly shown.
91 Two objects of the same type, but with different implicit/explicit tags
94 You can get object's effective tag (either default or implicited) through
95 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
98 >>> tag_decode(tag_ctxc(123))
100 >>> klass, form, num = tag_decode(tag_ctxc(123))
101 >>> klass == TagClassContext
103 >>> form == TagFormConstructed
106 To determine if object has explicit tag, use ``expled`` boolean property
107 and ``expl_tag`` property, returning explicit tag's value.
112 Many objects in sequences could be ``OPTIONAL`` and could have
113 ``DEFAULT`` value. You can specify that object's property using
114 corresponding keyword arguments.
116 >>> Integer(optional=True, default=123)
117 INTEGER 123 OPTIONAL DEFAULT
119 Those specifications do not play any role in primitive value encoding,
120 but are taken into account when dealing with sequences holding them. For
121 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
124 class Version(Integer):
130 class TBSCertificate(Sequence):
132 ("version", Version(expl=tag_ctxc(0), default="v1")),
135 When default argument is used and value is not specified, then it equals
143 Some objects give ability to set value size constraints. This is either
144 possible integer value, or allowed length of various strings and
145 sequences. Constraints are set in the following way::
150 And values satisfaction is checked as: ``MIN <= X <= MAX``.
152 For simplicity you can also set bounds the following way::
154 bounded_x = X(bounds=(MIN, MAX))
156 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
162 All objects have ``ready`` boolean property, that tells if object is
163 ready to be encoded. If that kind of action is performed on unready
164 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
166 All objects have ``copy()`` method, that returns their copy, that can be
174 Decoding is performed using ``decode()`` method. ``offset`` optional
175 argument could be used to set initial object's offset in the binary
176 data, for convenience. It returns decoded object and remaining
177 unmarshalled data (tail). Internally all work is done on
178 ``memoryview(data)``, and you can leave returning tail as a memoryview,
179 by specifying ``leavemm=True`` argument.
181 When object is decoded, ``decoded`` property is true and you can safely
182 use following properties:
184 * ``offset`` -- position including initial offset where object's tag starts
185 * ``tlen`` -- length of object's tag
186 * ``llen`` -- length of object's length value
187 * ``vlen`` -- length of object's value
188 * ``tlvlen`` -- length of the whole object
190 Pay attention that those values do **not** include anything related to
191 explicit tag. If you want to know information about it, then use:
193 * ``expled`` -- to know if explicit tag is set
194 * ``expl_offset`` (it is lesser than ``offset``)
197 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
198 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
200 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
203 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
210 You can specify so called context keyword argument during ``decode()``
211 invocation. It is dictionary containing various options governing
214 Currently available context options:
216 * :ref:`allow_default_values <allow_default_values_ctx>`
217 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
218 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
219 * :ref:`bered <bered_ctx>`
220 * :ref:`defines_by_path <defines_by_path_ctx>`
227 All objects have ``pps()`` method, that is a generator of
228 :py:class:`pyderasn.PP` namedtuple, holding various raw information
229 about the object. If ``pps`` is called on sequences, then all underlying
230 ``PP`` will be yielded.
232 You can use :py:func:`pyderasn.pp_console_row` function, converting
233 those ``PP`` to human readable string. Actually exactly it is used for
234 all object ``repr``. But it is easy to write custom formatters.
236 >>> from pyderasn import pprint
237 >>> encoded = Integer(-12345).encode()
238 >>> obj, tail = Integer().decode(encoded)
239 >>> print(pprint(obj))
240 0 [1,1, 2] INTEGER -12345
247 ASN.1 structures often have ANY and OCTET STRING fields, that are
248 DEFINED BY some previously met ObjectIdentifier. This library provides
249 ability to specify mapping between some OID and field that must be
250 decoded with specific specification.
255 :py:class:`pyderasn.ObjectIdentifier` field inside
256 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
257 necessary for decoding structures. For example, CMS (:rfc:`5652`)
260 class ContentInfo(Sequence):
262 ("contentType", ContentType(defines=((("content",), {
263 id_digestedData: DigestedData(),
264 id_signedData: SignedData(),
266 ("content", Any(expl=tag_ctxc(0))),
269 ``contentType`` field tells that it defines that ``content`` must be
270 decoded with ``SignedData`` specification, if ``contentType`` equals to
271 ``id-signedData``. The same applies to ``DigestedData``. If
272 ``contentType`` contains unknown OID, then no automatic decoding is
275 You can specify multiple fields, that will be autodecoded -- that is why
276 ``defines`` kwarg is a sequence. You can specify defined field
277 relatively or absolutely to current decode path. For example ``defines``
278 for AlgorithmIdentifier of X.509's
279 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
283 id_ecPublicKey: ECParameters(),
284 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
286 (("..", "subjectPublicKey"), {
287 id_rsaEncryption: RSAPublicKey(),
288 id_GostR3410_2001: OctetString(),
292 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
293 autodecode its parameters inside SPKI's algorithm and its public key
296 Following types can be automatically decoded (DEFINED BY):
298 * :py:class:`pyderasn.Any`
299 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
300 * :py:class:`pyderasn.OctetString`
301 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
302 ``Any``/``BitString``/``OctetString``-s
304 When any of those fields is automatically decoded, then ``.defined``
305 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
306 was defined, ``value`` contains corresponding decoded value. For example
307 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
309 .. _defines_by_path_ctx:
311 defines_by_path context option
312 ______________________________
314 Sometimes you either can not or do not want to explicitly set *defines*
315 in the scheme. You can dynamically apply those definitions when calling
316 ``.decode()`` method.
318 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
319 value must be sequence of following tuples::
321 (decode_path, defines)
323 where ``decode_path`` is a tuple holding so-called decode path to the
324 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
325 ``defines``, holding exactly the same value as accepted in its keyword
328 For example, again for CMS, you want to automatically decode
329 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
330 structures it may hold. Also, automatically decode ``controlSequence``
333 content_info, tail = ContentInfo().decode(data, defines_by_path=(
336 ((("content",), {id_signedData: SignedData()}),),
341 DecodePathDefBy(id_signedData),
346 id_cct_PKIData: PKIData(),
347 id_cct_PKIResponse: PKIResponse(),
353 DecodePathDefBy(id_signedData),
356 DecodePathDefBy(id_cct_PKIResponse),
362 id_cmc_recipientNonce: RecipientNonce(),
363 id_cmc_senderNonce: SenderNonce(),
364 id_cmc_statusInfoV2: CMCStatusInfoV2(),
365 id_cmc_transactionId: TransactionId(),
370 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
371 First function is useful for path construction when some automatic
372 decoding is already done. ``any`` means literally any value it meet --
373 useful for SEQUENCE/SET OF-s.
380 By default PyDERASN accepts only DER encoded data. It always encodes to
381 DER. But you can optionally enable BER decoding with setting ``bered``
382 :ref:`context <ctx>` argument to True. Indefinite lengths and
383 constructed primitive types should be parsed successfully.
385 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
386 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
387 STRING``, ``SEQUENCE``, ``SET``, ``SET OF`` can contain it.
388 * If object has an indefinite length encoding, then its ``lenindef``
389 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
390 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
392 * If object has an indefinite length encoded explicit tag, then
393 ``expl_lenindef`` is set to True.
394 * If object has either any of BER-related encoding (explicit tag
395 indefinite length, object's indefinite length, BER-encoding) or any
396 underlying component has that kind of encoding, then ``bered``
397 attribute is set to True. For example SignedData CMS can have
398 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
399 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
401 EOC (end-of-contents) token's length is taken in advance in object's
404 .. _allow_expl_oob_ctx:
406 Allow explicit tag out-of-bound
407 -------------------------------
409 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
410 one value, more than one object. If you set ``allow_expl_oob`` context
411 option to True, then no error will be raised and that invalid encoding
412 will be silently further processed. But pay attention that offsets and
413 lengths will be invalid in that case.
417 This option should be used only for skipping some decode errors, just
418 to see the decoded structure somehow.
425 .. autoclass:: pyderasn.Boolean
430 .. autoclass:: pyderasn.Integer
435 .. autoclass:: pyderasn.BitString
440 .. autoclass:: pyderasn.OctetString
445 .. autoclass:: pyderasn.Null
450 .. autoclass:: pyderasn.ObjectIdentifier
455 .. autoclass:: pyderasn.Enumerated
459 .. autoclass:: pyderasn.CommonString
463 .. autoclass:: pyderasn.NumericString
467 .. autoclass:: pyderasn.UTCTime
468 :members: __init__, todatetime
472 .. autoclass:: pyderasn.GeneralizedTime
479 .. autoclass:: pyderasn.Choice
484 .. autoclass:: PrimitiveTypes
488 .. autoclass:: pyderasn.Any
496 .. autoclass:: pyderasn.Sequence
501 .. autoclass:: pyderasn.Set
506 .. autoclass:: pyderasn.SequenceOf
511 .. autoclass:: pyderasn.SetOf
517 .. autofunction:: pyderasn.abs_decode_path
518 .. autofunction:: pyderasn.hexenc
519 .. autofunction:: pyderasn.hexdec
520 .. autofunction:: pyderasn.tag_encode
521 .. autofunction:: pyderasn.tag_decode
522 .. autofunction:: pyderasn.tag_ctxp
523 .. autofunction:: pyderasn.tag_ctxc
524 .. autoclass:: pyderasn.Obj
525 .. autoclass:: pyderasn.DecodeError
527 .. autoclass:: pyderasn.NotEnoughData
528 .. autoclass:: pyderasn.LenIndefForm
529 .. autoclass:: pyderasn.TagMismatch
530 .. autoclass:: pyderasn.InvalidLength
531 .. autoclass:: pyderasn.InvalidOID
532 .. autoclass:: pyderasn.ObjUnknown
533 .. autoclass:: pyderasn.ObjNotReady
534 .. autoclass:: pyderasn.InvalidValueType
535 .. autoclass:: pyderasn.BoundsError
538 from codecs import getdecoder
539 from codecs import getencoder
540 from collections import namedtuple
541 from collections import OrderedDict
542 from datetime import datetime
543 from math import ceil
544 from os import environ
545 from string import ascii_letters
546 from string import digits
548 from six import add_metaclass
549 from six import binary_type
550 from six import byte2int
551 from six import indexbytes
552 from six import int2byte
553 from six import integer_types
554 from six import iterbytes
556 from six import string_types
557 from six import text_type
558 from six.moves import xrange as six_xrange
562 from termcolor import colored
563 except ImportError: # pragma: no cover
564 def colored(what, *args):
608 "TagClassApplication",
612 "TagFormConstructed",
623 TagClassUniversal = 0
624 TagClassApplication = 1 << 6
625 TagClassContext = 1 << 7
626 TagClassPrivate = 1 << 6 | 1 << 7
628 TagFormConstructed = 1 << 5
631 TagClassApplication: "APPLICATION ",
632 TagClassPrivate: "PRIVATE ",
633 TagClassUniversal: "UNIV ",
637 LENINDEF = b"\x80" # length indefinite mark
638 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
641 ########################################################################
643 ########################################################################
645 class ASN1Error(ValueError):
648 class DecodeError(ASN1Error):
649 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
651 :param str msg: reason of decode failing
652 :param klass: optional exact DecodeError inherited class (like
653 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
654 :py:exc:`InvalidLength`)
655 :param decode_path: tuple of strings. It contains human
656 readable names of the fields through which
657 decoding process has passed
658 :param int offset: binary offset where failure happened
660 super(DecodeError, self).__init__()
663 self.decode_path = decode_path
669 "" if self.klass is None else self.klass.__name__,
671 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
672 if len(self.decode_path) > 0 else ""
674 ("(at %d)" % self.offset) if self.offset > 0 else "",
680 return "%s(%s)" % (self.__class__.__name__, self)
683 class NotEnoughData(DecodeError):
687 class LenIndefForm(DecodeError):
691 class TagMismatch(DecodeError):
695 class InvalidLength(DecodeError):
699 class InvalidOID(DecodeError):
703 class ObjUnknown(ASN1Error):
704 def __init__(self, name):
705 super(ObjUnknown, self).__init__()
709 return "object is unknown: %s" % self.name
712 return "%s(%s)" % (self.__class__.__name__, self)
715 class ObjNotReady(ASN1Error):
716 def __init__(self, name):
717 super(ObjNotReady, self).__init__()
721 return "object is not ready: %s" % self.name
724 return "%s(%s)" % (self.__class__.__name__, self)
727 class InvalidValueType(ASN1Error):
728 def __init__(self, expected_types):
729 super(InvalidValueType, self).__init__()
730 self.expected_types = expected_types
733 return "invalid value type, expected: %s" % ", ".join(
734 [repr(t) for t in self.expected_types]
738 return "%s(%s)" % (self.__class__.__name__, self)
741 class BoundsError(ASN1Error):
742 def __init__(self, bound_min, value, bound_max):
743 super(BoundsError, self).__init__()
744 self.bound_min = bound_min
746 self.bound_max = bound_max
749 return "unsatisfied bounds: %s <= %s <= %s" % (
756 return "%s(%s)" % (self.__class__.__name__, self)
759 ########################################################################
761 ########################################################################
763 _hexdecoder = getdecoder("hex")
764 _hexencoder = getencoder("hex")
768 """Binary data to hexadecimal string convert
770 return _hexdecoder(data)[0]
774 """Hexadecimal string to binary data convert
776 return _hexencoder(data)[0].decode("ascii")
779 def int_bytes_len(num, byte_len=8):
782 return int(ceil(float(num.bit_length()) / byte_len))
785 def zero_ended_encode(num):
786 octets = bytearray(int_bytes_len(num, 7))
788 octets[i] = num & 0x7F
792 octets[i] = 0x80 | (num & 0x7F)
798 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
799 """Encode tag to binary form
801 :param int num: tag's number
802 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
803 :py:data:`pyderasn.TagClassContext`,
804 :py:data:`pyderasn.TagClassApplication`,
805 :py:data:`pyderasn.TagClassPrivate`)
806 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
807 :py:data:`pyderasn.TagFormConstructed`)
811 return int2byte(klass | form | num)
812 # [XX|X|11111][1.......][1.......] ... [0.......]
813 return int2byte(klass | form | 31) + zero_ended_encode(num)
817 """Decode tag from binary form
821 No validation is performed, assuming that it has already passed.
823 It returns tuple with three integers, as
824 :py:func:`pyderasn.tag_encode` accepts.
826 first_octet = byte2int(tag)
827 klass = first_octet & 0xC0
828 form = first_octet & 0x20
829 if first_octet & 0x1F < 0x1F:
830 return (klass, form, first_octet & 0x1F)
832 for octet in iterbytes(tag[1:]):
835 return (klass, form, num)
839 """Create CONTEXT PRIMITIVE tag
841 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
845 """Create CONTEXT CONSTRUCTED tag
847 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
851 """Take off tag from the data
853 :returns: (encoded tag, tag length, remaining data)
856 raise NotEnoughData("no data at all")
857 if byte2int(data) & 0x1F < 31:
858 return data[:1], 1, data[1:]
863 raise DecodeError("unfinished tag")
864 if indexbytes(data, i) & 0x80 == 0:
867 return data[:i], i, data[i:]
873 octets = bytearray(int_bytes_len(l) + 1)
874 octets[0] = 0x80 | (len(octets) - 1)
875 for i in six_xrange(len(octets) - 1, 0, -1):
881 def len_decode(data):
884 :returns: (decoded length, length's length, remaining data)
885 :raises LenIndefForm: if indefinite form encoding is met
888 raise NotEnoughData("no data at all")
889 first_octet = byte2int(data)
890 if first_octet & 0x80 == 0:
891 return first_octet, 1, data[1:]
892 octets_num = first_octet & 0x7F
893 if octets_num + 1 > len(data):
894 raise NotEnoughData("encoded length is longer than data")
897 if byte2int(data[1:]) == 0:
898 raise DecodeError("leading zeros")
900 for v in iterbytes(data[1:1 + octets_num]):
903 raise DecodeError("long form instead of short one")
904 return l, 1 + octets_num, data[1 + octets_num:]
907 ########################################################################
909 ########################################################################
911 class AutoAddSlots(type):
912 def __new__(mcs, name, bases, _dict):
913 _dict["__slots__"] = _dict.get("__slots__", ())
914 return type.__new__(mcs, name, bases, _dict)
917 @add_metaclass(AutoAddSlots)
919 """Common ASN.1 object class
921 All ASN.1 types are inherited from it. It has metaclass that
922 automatically adds ``__slots__`` to all inherited classes.
946 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
947 self._expl = getattr(self, "expl", None) if expl is None else expl
948 if self.tag != self.tag_default and self._expl is not None:
949 raise ValueError("implicit and explicit tags can not be set simultaneously")
950 if default is not None:
952 self.optional = optional
953 self.offset, self.llen, self.vlen = _decoded
955 self.expl_lenindef = False
956 self.lenindef = False
957 self.ber_encoded = False
960 def ready(self): # pragma: no cover
961 """Is object ready to be encoded?
963 raise NotImplementedError()
965 def _assert_ready(self):
967 raise ObjNotReady(self.__class__.__name__)
971 """Is either object or any elements inside is BER encoded?
973 return self.expl_lenindef or self.lenindef or self.ber_encoded
977 """Is object decoded?
979 return (self.llen + self.vlen) > 0
981 def copy(self): # pragma: no cover
982 """Make a copy of object, safe to be mutated
984 raise NotImplementedError()
992 return self.tlen + self.llen + self.vlen
994 def __str__(self): # pragma: no cover
995 return self.__bytes__() if PY2 else self.__unicode__()
997 def __ne__(self, their):
998 return not(self == their)
1000 def __gt__(self, their): # pragma: no cover
1001 return not(self < their)
1003 def __le__(self, their): # pragma: no cover
1004 return (self == their) or (self < their)
1006 def __ge__(self, their): # pragma: no cover
1007 return (self == their) or (self > their)
1009 def _encode(self): # pragma: no cover
1010 raise NotImplementedError()
1012 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1013 raise NotImplementedError()
1016 raw = self._encode()
1017 if self._expl is None:
1019 return b"".join((self._expl, len_encode(len(raw)), raw))
1032 :param data: either binary or memoryview
1033 :param int offset: initial data's offset
1034 :param bool leavemm: do we need to leave memoryview of remaining
1035 data as is, or convert it to bytes otherwise
1036 :param ctx: optional :ref:`context <ctx>` governing decoding process.
1037 :param tag_only: decode only the tag, without length and contents
1038 (used only in Choice and Set structures, trying to
1039 determine if tag satisfies the scheme)
1040 :returns: (Obj, remaining data)
1044 tlv = memoryview(data)
1045 if self._expl is None:
1046 result = self._decode(
1049 decode_path=decode_path,
1058 t, tlen, lv = tag_strip(tlv)
1059 except DecodeError as err:
1060 raise err.__class__(
1062 klass=self.__class__,
1063 decode_path=decode_path,
1068 klass=self.__class__,
1069 decode_path=decode_path,
1073 l, llen, v = len_decode(lv)
1074 except LenIndefForm as err:
1075 if not ctx.get("bered", False):
1076 raise err.__class__(
1078 klass=self.__class__,
1079 decode_path=decode_path,
1083 offset += tlen + llen
1084 result = self._decode(
1087 decode_path=decode_path,
1091 if tag_only: # pragma: no cover
1094 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1095 if eoc_expected.tobytes() != EOC:
1098 klass=self.__class__,
1099 decode_path=decode_path,
1103 obj.expl_lenindef = True
1104 except DecodeError as err:
1105 raise err.__class__(
1107 klass=self.__class__,
1108 decode_path=decode_path,
1113 raise NotEnoughData(
1114 "encoded length is longer than data",
1115 klass=self.__class__,
1116 decode_path=decode_path,
1119 result = self._decode(
1121 offset=offset + tlen + llen,
1122 decode_path=decode_path,
1126 if tag_only: # pragma: no cover
1129 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1131 "explicit tag out-of-bound, longer than data",
1132 klass=self.__class__,
1133 decode_path=decode_path,
1136 return obj, (tail if leavemm else tail.tobytes())
1140 return self._expl is not None
1147 def expl_tlen(self):
1148 return len(self._expl)
1151 def expl_llen(self):
1152 if self.expl_lenindef:
1154 return len(len_encode(self.tlvlen))
1157 def expl_offset(self):
1158 return self.offset - self.expl_tlen - self.expl_llen
1161 def expl_vlen(self):
1165 def expl_tlvlen(self):
1166 return self.expl_tlen + self.expl_llen + self.expl_vlen
1169 def fulloffset(self):
1170 return self.expl_offset if self.expled else self.offset
1174 return self.expl_tlvlen if self.expled else self.tlvlen
1176 def pps_lenindef(self, decode_path):
1177 if self.lenindef and not (
1178 getattr(self, "defined", None) is not None and
1179 self.defined[1].lenindef
1182 asn1_type_name="EOC",
1184 decode_path=decode_path,
1186 self.offset + self.tlvlen -
1187 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1195 if self.expl_lenindef:
1197 asn1_type_name="EOC",
1198 obj_name="EXPLICIT",
1199 decode_path=decode_path,
1200 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1209 class DecodePathDefBy(object):
1210 """DEFINED BY representation inside decode path
1212 __slots__ = ("defined_by",)
1214 def __init__(self, defined_by):
1215 self.defined_by = defined_by
1217 def __ne__(self, their):
1218 return not(self == their)
1220 def __eq__(self, their):
1221 if not isinstance(their, self.__class__):
1223 return self.defined_by == their.defined_by
1226 return "DEFINED BY " + str(self.defined_by)
1229 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1232 ########################################################################
1234 ########################################################################
1236 PP = namedtuple("PP", (
1262 asn1_type_name="unknown",
1279 expl_lenindef=False,
1309 def _colourize(what, colour, with_colours, attrs=("bold",)):
1310 return colored(what, colour, attrs=attrs) if with_colours else what
1319 with_decode_path=False,
1320 decode_path_len_decrease=0,
1327 " " if pp.expl_offset is None else
1328 ("-%d" % (pp.offset - pp.expl_offset))
1330 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1332 col = _colourize(col, "red", with_colours, ())
1333 col += _colourize("B", "red", with_colours) if pp.bered else " "
1335 col = "[%d,%d,%4d]%s" % (
1339 LENINDEF_PP_CHAR if pp.lenindef else " "
1341 col = _colourize(col, "green", with_colours, ())
1343 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1344 if decode_path_len > 0:
1345 cols.append(" ." * decode_path_len)
1346 ent = pp.decode_path[-1]
1347 if isinstance(ent, DecodePathDefBy):
1348 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1349 value = str(ent.defined_by)
1351 oids is not None and
1352 ent.defined_by.asn1_type_name ==
1353 ObjectIdentifier.asn1_type_name and
1356 cols.append(_colourize("%s:" % oids[value], "green", with_colours))
1358 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1360 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1361 if pp.expl is not None:
1362 klass, _, num = pp.expl
1363 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1364 cols.append(_colourize(col, "blue", with_colours))
1365 if pp.impl is not None:
1366 klass, _, num = pp.impl
1367 col = "[%s%d]" % (TagClassReprs[klass], num)
1368 cols.append(_colourize(col, "blue", with_colours))
1369 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1370 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1372 cols.append(_colourize("BER", "red", with_colours))
1373 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1374 if pp.value is not None:
1376 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1378 oids is not None and
1379 pp.asn1_type_name == ObjectIdentifier.asn1_type_name and
1382 cols.append(_colourize("(%s)" % oids[value], "green", with_colours))
1384 if isinstance(pp.blob, binary_type):
1385 cols.append(hexenc(pp.blob))
1386 elif isinstance(pp.blob, tuple):
1387 cols.append(", ".join(pp.blob))
1389 cols.append(_colourize("OPTIONAL", "red", with_colours))
1391 cols.append(_colourize("DEFAULT", "red", with_colours))
1392 if with_decode_path:
1393 cols.append(_colourize(
1394 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1398 return " ".join(cols)
1401 def pp_console_blob(pp, decode_path_len_decrease=0):
1402 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1403 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1404 if decode_path_len > 0:
1405 cols.append(" ." * (decode_path_len + 1))
1406 if isinstance(pp.blob, binary_type):
1407 blob = hexenc(pp.blob).upper()
1408 for i in range(0, len(blob), 32):
1409 chunk = blob[i:i + 32]
1410 yield " ".join(cols + [":".join(
1411 chunk[j:j + 2] for j in range(0, len(chunk), 2)
1413 elif isinstance(pp.blob, tuple):
1414 yield " ".join(cols + [", ".join(pp.blob)])
1422 with_decode_path=False,
1423 decode_path_only=(),
1425 """Pretty print object
1427 :param Obj obj: object you want to pretty print
1428 :param oids: ``OID <-> humand readable string`` dictionary. When OID
1429 from it is met, then its humand readable form is printed
1430 :param big_blobs: if large binary objects are met (like OctetString
1431 values), do we need to print them too, on separate
1433 :param with_colours: colourize output, if ``termcolor`` library
1435 :param with_decode_path: print decode path
1436 :param decode_path_only: print only that specified decode path
1438 def _pprint_pps(pps):
1440 if hasattr(pp, "_fields"):
1442 decode_path_only != () and
1444 str(p) for p in pp.decode_path[:len(decode_path_only)]
1445 ) != decode_path_only
1449 yield pp_console_row(
1454 with_colours=with_colours,
1455 with_decode_path=with_decode_path,
1456 decode_path_len_decrease=len(decode_path_only),
1458 for row in pp_console_blob(
1460 decode_path_len_decrease=len(decode_path_only),
1464 yield pp_console_row(
1469 with_colours=with_colours,
1470 with_decode_path=with_decode_path,
1471 decode_path_len_decrease=len(decode_path_only),
1474 for row in _pprint_pps(pp):
1476 return "\n".join(_pprint_pps(obj.pps()))
1479 ########################################################################
1480 # ASN.1 primitive types
1481 ########################################################################
1484 """``BOOLEAN`` boolean type
1486 >>> b = Boolean(True)
1488 >>> b == Boolean(True)
1494 tag_default = tag_encode(1)
1495 asn1_type_name = "BOOLEAN"
1507 :param value: set the value. Either boolean type, or
1508 :py:class:`pyderasn.Boolean` object
1509 :param bytes impl: override default tag with ``IMPLICIT`` one
1510 :param bytes expl: override default tag with ``EXPLICIT`` one
1511 :param default: set default value. Type same as in ``value``
1512 :param bool optional: is object ``OPTIONAL`` in sequence
1514 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1515 self._value = None if value is None else self._value_sanitize(value)
1516 if default is not None:
1517 default = self._value_sanitize(default)
1518 self.default = self.__class__(
1524 self._value = default
1526 def _value_sanitize(self, value):
1527 if issubclass(value.__class__, Boolean):
1529 if isinstance(value, bool):
1531 raise InvalidValueType((self.__class__, bool))
1535 return self._value is not None
1538 obj = self.__class__()
1539 obj._value = self._value
1541 obj._expl = self._expl
1542 obj.default = self.default
1543 obj.optional = self.optional
1544 obj.offset = self.offset
1545 obj.llen = self.llen
1546 obj.vlen = self.vlen
1549 def __nonzero__(self):
1550 self._assert_ready()
1554 self._assert_ready()
1557 def __eq__(self, their):
1558 if isinstance(their, bool):
1559 return self._value == their
1560 if not issubclass(their.__class__, Boolean):
1563 self._value == their._value and
1564 self.tag == their.tag and
1565 self._expl == their._expl
1576 return self.__class__(
1578 impl=self.tag if impl is None else impl,
1579 expl=self._expl if expl is None else expl,
1580 default=self.default if default is None else default,
1581 optional=self.optional if optional is None else optional,
1585 self._assert_ready()
1589 (b"\xFF" if self._value else b"\x00"),
1592 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1594 t, _, lv = tag_strip(tlv)
1595 except DecodeError as err:
1596 raise err.__class__(
1598 klass=self.__class__,
1599 decode_path=decode_path,
1604 klass=self.__class__,
1605 decode_path=decode_path,
1611 l, _, v = len_decode(lv)
1612 except DecodeError as err:
1613 raise err.__class__(
1615 klass=self.__class__,
1616 decode_path=decode_path,
1620 raise InvalidLength(
1621 "Boolean's length must be equal to 1",
1622 klass=self.__class__,
1623 decode_path=decode_path,
1627 raise NotEnoughData(
1628 "encoded length is longer than data",
1629 klass=self.__class__,
1630 decode_path=decode_path,
1633 first_octet = byte2int(v)
1635 if first_octet == 0:
1637 elif first_octet == 0xFF:
1639 elif ctx.get("bered", False):
1644 "unacceptable Boolean value",
1645 klass=self.__class__,
1646 decode_path=decode_path,
1649 obj = self.__class__(
1653 default=self.default,
1654 optional=self.optional,
1655 _decoded=(offset, 1, 1),
1657 obj.ber_encoded = ber_encoded
1661 return pp_console_row(next(self.pps()))
1663 def pps(self, decode_path=()):
1665 asn1_type_name=self.asn1_type_name,
1666 obj_name=self.__class__.__name__,
1667 decode_path=decode_path,
1668 value=str(self._value) if self.ready else None,
1669 optional=self.optional,
1670 default=self == self.default,
1671 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1672 expl=None if self._expl is None else tag_decode(self._expl),
1677 expl_offset=self.expl_offset if self.expled else None,
1678 expl_tlen=self.expl_tlen if self.expled else None,
1679 expl_llen=self.expl_llen if self.expled else None,
1680 expl_vlen=self.expl_vlen if self.expled else None,
1681 expl_lenindef=self.expl_lenindef,
1682 ber_encoded=self.ber_encoded,
1685 for pp in self.pps_lenindef(decode_path):
1690 """``INTEGER`` integer type
1692 >>> b = Integer(-123)
1694 >>> b == Integer(-123)
1699 >>> Integer(2, bounds=(1, 3))
1701 >>> Integer(5, bounds=(1, 3))
1702 Traceback (most recent call last):
1703 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1707 class Version(Integer):
1714 >>> v = Version("v1")
1721 {'v3': 2, 'v1': 0, 'v2': 1}
1723 __slots__ = ("specs", "_bound_min", "_bound_max")
1724 tag_default = tag_encode(2)
1725 asn1_type_name = "INTEGER"
1739 :param value: set the value. Either integer type, named value
1740 (if ``schema`` is specified in the class), or
1741 :py:class:`pyderasn.Integer` object
1742 :param bounds: set ``(MIN, MAX)`` value constraint.
1743 (-inf, +inf) by default
1744 :param bytes impl: override default tag with ``IMPLICIT`` one
1745 :param bytes expl: override default tag with ``EXPLICIT`` one
1746 :param default: set default value. Type same as in ``value``
1747 :param bool optional: is object ``OPTIONAL`` in sequence
1749 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
1751 specs = getattr(self, "schema", {}) if _specs is None else _specs
1752 self.specs = specs if isinstance(specs, dict) else dict(specs)
1753 self._bound_min, self._bound_max = getattr(
1756 (float("-inf"), float("+inf")),
1757 ) if bounds is None else bounds
1758 if value is not None:
1759 self._value = self._value_sanitize(value)
1760 if default is not None:
1761 default = self._value_sanitize(default)
1762 self.default = self.__class__(
1768 if self._value is None:
1769 self._value = default
1771 def _value_sanitize(self, value):
1772 if issubclass(value.__class__, Integer):
1773 value = value._value
1774 elif isinstance(value, integer_types):
1776 elif isinstance(value, str):
1777 value = self.specs.get(value)
1779 raise ObjUnknown("integer value: %s" % value)
1781 raise InvalidValueType((self.__class__, int, str))
1782 if not self._bound_min <= value <= self._bound_max:
1783 raise BoundsError(self._bound_min, value, self._bound_max)
1788 return self._value is not None
1791 obj = self.__class__(_specs=self.specs)
1792 obj._value = self._value
1793 obj._bound_min = self._bound_min
1794 obj._bound_max = self._bound_max
1796 obj._expl = self._expl
1797 obj.default = self.default
1798 obj.optional = self.optional
1799 obj.offset = self.offset
1800 obj.llen = self.llen
1801 obj.vlen = self.vlen
1805 self._assert_ready()
1806 return int(self._value)
1809 self._assert_ready()
1812 bytes(self._expl or b"") +
1813 str(self._value).encode("ascii"),
1816 def __eq__(self, their):
1817 if isinstance(their, integer_types):
1818 return self._value == their
1819 if not issubclass(their.__class__, Integer):
1822 self._value == their._value and
1823 self.tag == their.tag and
1824 self._expl == their._expl
1827 def __lt__(self, their):
1828 return self._value < their._value
1832 for name, value in self.specs.items():
1833 if value == self._value:
1845 return self.__class__(
1848 (self._bound_min, self._bound_max)
1849 if bounds is None else bounds
1851 impl=self.tag if impl is None else impl,
1852 expl=self._expl if expl is None else expl,
1853 default=self.default if default is None else default,
1854 optional=self.optional if optional is None else optional,
1859 self._assert_ready()
1863 octets = bytearray([0])
1867 octets = bytearray()
1869 octets.append((value & 0xFF) ^ 0xFF)
1871 if len(octets) == 0 or octets[-1] & 0x80 == 0:
1874 octets = bytearray()
1876 octets.append(value & 0xFF)
1878 if octets[-1] & 0x80 > 0:
1881 octets = bytes(octets)
1883 bytes_len = ceil(value.bit_length() / 8) or 1
1886 octets = value.to_bytes(
1891 except OverflowError:
1895 return b"".join((self.tag, len_encode(len(octets)), octets))
1897 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1899 t, _, lv = tag_strip(tlv)
1900 except DecodeError as err:
1901 raise err.__class__(
1903 klass=self.__class__,
1904 decode_path=decode_path,
1909 klass=self.__class__,
1910 decode_path=decode_path,
1916 l, llen, v = len_decode(lv)
1917 except DecodeError as err:
1918 raise err.__class__(
1920 klass=self.__class__,
1921 decode_path=decode_path,
1925 raise NotEnoughData(
1926 "encoded length is longer than data",
1927 klass=self.__class__,
1928 decode_path=decode_path,
1932 raise NotEnoughData(
1934 klass=self.__class__,
1935 decode_path=decode_path,
1938 v, tail = v[:l], v[l:]
1939 first_octet = byte2int(v)
1941 second_octet = byte2int(v[1:])
1943 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
1944 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
1947 "non normalized integer",
1948 klass=self.__class__,
1949 decode_path=decode_path,
1954 if first_octet & 0x80 > 0:
1955 octets = bytearray()
1956 for octet in bytearray(v):
1957 octets.append(octet ^ 0xFF)
1958 for octet in octets:
1959 value = (value << 8) | octet
1963 for octet in bytearray(v):
1964 value = (value << 8) | octet
1966 value = int.from_bytes(v, byteorder="big", signed=True)
1968 obj = self.__class__(
1970 bounds=(self._bound_min, self._bound_max),
1973 default=self.default,
1974 optional=self.optional,
1976 _decoded=(offset, llen, l),
1978 except BoundsError as err:
1981 klass=self.__class__,
1982 decode_path=decode_path,
1988 return pp_console_row(next(self.pps()))
1990 def pps(self, decode_path=()):
1992 asn1_type_name=self.asn1_type_name,
1993 obj_name=self.__class__.__name__,
1994 decode_path=decode_path,
1995 value=(self.named or str(self._value)) if self.ready else None,
1996 optional=self.optional,
1997 default=self == self.default,
1998 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1999 expl=None if self._expl is None else tag_decode(self._expl),
2004 expl_offset=self.expl_offset if self.expled else None,
2005 expl_tlen=self.expl_tlen if self.expled else None,
2006 expl_llen=self.expl_llen if self.expled else None,
2007 expl_vlen=self.expl_vlen if self.expled else None,
2008 expl_lenindef=self.expl_lenindef,
2011 for pp in self.pps_lenindef(decode_path):
2015 class BitString(Obj):
2016 """``BIT STRING`` bit string type
2018 >>> BitString(b"hello world")
2019 BIT STRING 88 bits 68656c6c6f20776f726c64
2022 >>> b == b"hello world"
2027 >>> BitString("'0A3B5F291CD'H")
2028 BIT STRING 44 bits 0a3b5f291cd0
2029 >>> b = BitString("'010110000000'B")
2030 BIT STRING 12 bits 5800
2033 >>> b[0], b[1], b[2], b[3]
2034 (False, True, False, True)
2038 [False, True, False, True, True, False, False, False, False, False, False, False]
2042 class KeyUsage(BitString):
2044 ("digitalSignature", 0),
2045 ("nonRepudiation", 1),
2046 ("keyEncipherment", 2),
2049 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2050 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2052 ['nonRepudiation', 'keyEncipherment']
2054 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2058 Pay attention that BIT STRING can be encoded both in primitive
2059 and constructed forms. Decoder always checks constructed form tag
2060 additionally to specified primitive one. If BER decoding is
2061 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2062 of DER restrictions.
2064 __slots__ = ("tag_constructed", "specs", "defined")
2065 tag_default = tag_encode(3)
2066 asn1_type_name = "BIT STRING"
2079 :param value: set the value. Either binary type, tuple of named
2080 values (if ``schema`` is specified in the class),
2081 string in ``'XXX...'B`` form, or
2082 :py:class:`pyderasn.BitString` object
2083 :param bytes impl: override default tag with ``IMPLICIT`` one
2084 :param bytes expl: override default tag with ``EXPLICIT`` one
2085 :param default: set default value. Type same as in ``value``
2086 :param bool optional: is object ``OPTIONAL`` in sequence
2088 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2089 specs = getattr(self, "schema", {}) if _specs is None else _specs
2090 self.specs = specs if isinstance(specs, dict) else dict(specs)
2091 self._value = None if value is None else self._value_sanitize(value)
2092 if default is not None:
2093 default = self._value_sanitize(default)
2094 self.default = self.__class__(
2100 self._value = default
2102 tag_klass, _, tag_num = tag_decode(self.tag)
2103 self.tag_constructed = tag_encode(
2105 form=TagFormConstructed,
2109 def _bits2octets(self, bits):
2110 if len(self.specs) > 0:
2111 bits = bits.rstrip("0")
2113 bits += "0" * ((8 - (bit_len % 8)) % 8)
2114 octets = bytearray(len(bits) // 8)
2115 for i in six_xrange(len(octets)):
2116 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2117 return bit_len, bytes(octets)
2119 def _value_sanitize(self, value):
2120 if issubclass(value.__class__, BitString):
2122 if isinstance(value, (string_types, binary_type)):
2124 isinstance(value, string_types) and
2125 value.startswith("'")
2127 if value.endswith("'B"):
2129 if not set(value) <= set(("0", "1")):
2130 raise ValueError("B's coding contains unacceptable chars")
2131 return self._bits2octets(value)
2132 elif value.endswith("'H"):
2136 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2138 if isinstance(value, binary_type):
2139 return (len(value) * 8, value)
2141 raise InvalidValueType((self.__class__, string_types, binary_type))
2142 if isinstance(value, tuple):
2145 isinstance(value[0], integer_types) and
2146 isinstance(value[1], binary_type)
2151 bit = self.specs.get(name)
2153 raise ObjUnknown("BitString value: %s" % name)
2156 return self._bits2octets("")
2158 return self._bits2octets("".join(
2159 ("1" if bit in bits else "0")
2160 for bit in six_xrange(max(bits) + 1)
2162 raise InvalidValueType((self.__class__, binary_type, string_types))
2166 return self._value is not None
2169 obj = self.__class__(_specs=self.specs)
2171 if value is not None:
2172 value = (value[0], value[1])
2175 obj._expl = self._expl
2176 obj.default = self.default
2177 obj.optional = self.optional
2178 obj.offset = self.offset
2179 obj.llen = self.llen
2180 obj.vlen = self.vlen
2184 self._assert_ready()
2185 for i in six_xrange(self._value[0]):
2190 self._assert_ready()
2191 return self._value[0]
2193 def __bytes__(self):
2194 self._assert_ready()
2195 return self._value[1]
2197 def __eq__(self, their):
2198 if isinstance(their, bytes):
2199 return self._value[1] == their
2200 if not issubclass(their.__class__, BitString):
2203 self._value == their._value and
2204 self.tag == their.tag and
2205 self._expl == their._expl
2210 return [name for name, bit in self.specs.items() if self[bit]]
2220 return self.__class__(
2222 impl=self.tag if impl is None else impl,
2223 expl=self._expl if expl is None else expl,
2224 default=self.default if default is None else default,
2225 optional=self.optional if optional is None else optional,
2229 def __getitem__(self, key):
2230 if isinstance(key, int):
2231 bit_len, octets = self._value
2235 byte2int(memoryview(octets)[key // 8:]) >>
2238 if isinstance(key, string_types):
2239 value = self.specs.get(key)
2241 raise ObjUnknown("BitString value: %s" % key)
2243 raise InvalidValueType((int, str))
2246 self._assert_ready()
2247 bit_len, octets = self._value
2250 len_encode(len(octets) + 1),
2251 int2byte((8 - bit_len % 8) % 8),
2255 def _decode_chunk(self, lv, offset, decode_path, ctx):
2257 l, llen, v = len_decode(lv)
2258 except DecodeError as err:
2259 raise err.__class__(
2261 klass=self.__class__,
2262 decode_path=decode_path,
2266 raise NotEnoughData(
2267 "encoded length is longer than data",
2268 klass=self.__class__,
2269 decode_path=decode_path,
2273 raise NotEnoughData(
2275 klass=self.__class__,
2276 decode_path=decode_path,
2279 pad_size = byte2int(v)
2280 if l == 1 and pad_size != 0:
2282 "invalid empty value",
2283 klass=self.__class__,
2284 decode_path=decode_path,
2290 klass=self.__class__,
2291 decode_path=decode_path,
2294 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2297 klass=self.__class__,
2298 decode_path=decode_path,
2301 v, tail = v[:l], v[l:]
2302 obj = self.__class__(
2303 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2306 default=self.default,
2307 optional=self.optional,
2309 _decoded=(offset, llen, l),
2313 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2315 t, tlen, lv = tag_strip(tlv)
2316 except DecodeError as err:
2317 raise err.__class__(
2319 klass=self.__class__,
2320 decode_path=decode_path,
2324 if tag_only: # pragma: no cover
2326 return self._decode_chunk(lv, offset, decode_path, ctx)
2327 if t == self.tag_constructed:
2328 if not ctx.get("bered", False):
2330 "unallowed BER constructed encoding",
2331 klass=self.__class__,
2332 decode_path=decode_path,
2335 if tag_only: # pragma: no cover
2339 l, llen, v = len_decode(lv)
2340 except LenIndefForm:
2341 llen, l, v = 1, 0, lv[1:]
2343 except DecodeError as err:
2344 raise err.__class__(
2346 klass=self.__class__,
2347 decode_path=decode_path,
2351 raise NotEnoughData(
2352 "encoded length is longer than data",
2353 klass=self.__class__,
2354 decode_path=decode_path,
2357 if not lenindef and l == 0:
2358 raise NotEnoughData(
2360 klass=self.__class__,
2361 decode_path=decode_path,
2365 sub_offset = offset + tlen + llen
2369 if v[:EOC_LEN].tobytes() == EOC:
2376 "chunk out of bounds",
2377 klass=self.__class__,
2378 decode_path=decode_path + (str(len(chunks) - 1),),
2379 offset=chunks[-1].offset,
2381 sub_decode_path = decode_path + (str(len(chunks)),)
2383 chunk, v_tail = BitString().decode(
2386 decode_path=sub_decode_path,
2392 "expected BitString encoded chunk",
2393 klass=self.__class__,
2394 decode_path=sub_decode_path,
2397 chunks.append(chunk)
2398 sub_offset += chunk.tlvlen
2399 vlen += chunk.tlvlen
2401 if len(chunks) == 0:
2404 klass=self.__class__,
2405 decode_path=decode_path,
2410 for chunk_i, chunk in enumerate(chunks[:-1]):
2411 if chunk.bit_len % 8 != 0:
2413 "BitString chunk is not multiple of 8 bits",
2414 klass=self.__class__,
2415 decode_path=decode_path + (str(chunk_i),),
2416 offset=chunk.offset,
2418 values.append(bytes(chunk))
2419 bit_len += chunk.bit_len
2420 chunk_last = chunks[-1]
2421 values.append(bytes(chunk_last))
2422 bit_len += chunk_last.bit_len
2423 obj = self.__class__(
2424 value=(bit_len, b"".join(values)),
2427 default=self.default,
2428 optional=self.optional,
2430 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2432 obj.lenindef = lenindef
2433 obj.ber_encoded = True
2434 return obj, (v[EOC_LEN:] if lenindef else v)
2436 klass=self.__class__,
2437 decode_path=decode_path,
2442 return pp_console_row(next(self.pps()))
2444 def pps(self, decode_path=()):
2448 bit_len, blob = self._value
2449 value = "%d bits" % bit_len
2450 if len(self.specs) > 0:
2451 blob = tuple(self.named)
2453 asn1_type_name=self.asn1_type_name,
2454 obj_name=self.__class__.__name__,
2455 decode_path=decode_path,
2458 optional=self.optional,
2459 default=self == self.default,
2460 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2461 expl=None if self._expl is None else tag_decode(self._expl),
2466 expl_offset=self.expl_offset if self.expled else None,
2467 expl_tlen=self.expl_tlen if self.expled else None,
2468 expl_llen=self.expl_llen if self.expled else None,
2469 expl_vlen=self.expl_vlen if self.expled else None,
2470 expl_lenindef=self.expl_lenindef,
2471 lenindef=self.lenindef,
2472 ber_encoded=self.ber_encoded,
2475 defined_by, defined = self.defined or (None, None)
2476 if defined_by is not None:
2478 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2480 for pp in self.pps_lenindef(decode_path):
2484 class OctetString(Obj):
2485 """``OCTET STRING`` binary string type
2487 >>> s = OctetString(b"hello world")
2488 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2489 >>> s == OctetString(b"hello world")
2494 >>> OctetString(b"hello", bounds=(4, 4))
2495 Traceback (most recent call last):
2496 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2497 >>> OctetString(b"hell", bounds=(4, 4))
2498 OCTET STRING 4 bytes 68656c6c
2502 Pay attention that OCTET STRING can be encoded both in primitive
2503 and constructed forms. Decoder always checks constructed form tag
2504 additionally to specified primitive one. If BER decoding is
2505 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2506 of DER restrictions.
2508 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2509 tag_default = tag_encode(4)
2510 asn1_type_name = "OCTET STRING"
2523 :param value: set the value. Either binary type, or
2524 :py:class:`pyderasn.OctetString` object
2525 :param bounds: set ``(MIN, MAX)`` value size constraint.
2526 (-inf, +inf) by default
2527 :param bytes impl: override default tag with ``IMPLICIT`` one
2528 :param bytes expl: override default tag with ``EXPLICIT`` one
2529 :param default: set default value. Type same as in ``value``
2530 :param bool optional: is object ``OPTIONAL`` in sequence
2532 super(OctetString, self).__init__(
2540 self._bound_min, self._bound_max = getattr(
2544 ) if bounds is None else bounds
2545 if value is not None:
2546 self._value = self._value_sanitize(value)
2547 if default is not None:
2548 default = self._value_sanitize(default)
2549 self.default = self.__class__(
2554 if self._value is None:
2555 self._value = default
2557 tag_klass, _, tag_num = tag_decode(self.tag)
2558 self.tag_constructed = tag_encode(
2560 form=TagFormConstructed,
2564 def _value_sanitize(self, value):
2565 if issubclass(value.__class__, OctetString):
2566 value = value._value
2567 elif isinstance(value, binary_type):
2570 raise InvalidValueType((self.__class__, bytes))
2571 if not self._bound_min <= len(value) <= self._bound_max:
2572 raise BoundsError(self._bound_min, len(value), self._bound_max)
2577 return self._value is not None
2580 obj = self.__class__()
2581 obj._value = self._value
2582 obj._bound_min = self._bound_min
2583 obj._bound_max = self._bound_max
2585 obj._expl = self._expl
2586 obj.default = self.default
2587 obj.optional = self.optional
2588 obj.offset = self.offset
2589 obj.llen = self.llen
2590 obj.vlen = self.vlen
2593 def __bytes__(self):
2594 self._assert_ready()
2597 def __eq__(self, their):
2598 if isinstance(their, binary_type):
2599 return self._value == their
2600 if not issubclass(their.__class__, OctetString):
2603 self._value == their._value and
2604 self.tag == their.tag and
2605 self._expl == their._expl
2608 def __lt__(self, their):
2609 return self._value < their._value
2620 return self.__class__(
2623 (self._bound_min, self._bound_max)
2624 if bounds is None else bounds
2626 impl=self.tag if impl is None else impl,
2627 expl=self._expl if expl is None else expl,
2628 default=self.default if default is None else default,
2629 optional=self.optional if optional is None else optional,
2633 self._assert_ready()
2636 len_encode(len(self._value)),
2640 def _decode_chunk(self, lv, offset, decode_path, ctx):
2642 l, llen, v = len_decode(lv)
2643 except DecodeError as err:
2644 raise err.__class__(
2646 klass=self.__class__,
2647 decode_path=decode_path,
2651 raise NotEnoughData(
2652 "encoded length is longer than data",
2653 klass=self.__class__,
2654 decode_path=decode_path,
2657 v, tail = v[:l], v[l:]
2659 obj = self.__class__(
2661 bounds=(self._bound_min, self._bound_max),
2664 default=self.default,
2665 optional=self.optional,
2666 _decoded=(offset, llen, l),
2668 except DecodeError as err:
2671 klass=self.__class__,
2672 decode_path=decode_path,
2675 except BoundsError as err:
2678 klass=self.__class__,
2679 decode_path=decode_path,
2684 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2686 t, tlen, lv = tag_strip(tlv)
2687 except DecodeError as err:
2688 raise err.__class__(
2690 klass=self.__class__,
2691 decode_path=decode_path,
2697 return self._decode_chunk(lv, offset, decode_path, ctx)
2698 if t == self.tag_constructed:
2699 if not ctx.get("bered", False):
2701 "unallowed BER constructed encoding",
2702 klass=self.__class__,
2703 decode_path=decode_path,
2710 l, llen, v = len_decode(lv)
2711 except LenIndefForm:
2712 llen, l, v = 1, 0, lv[1:]
2714 except DecodeError as err:
2715 raise err.__class__(
2717 klass=self.__class__,
2718 decode_path=decode_path,
2722 raise NotEnoughData(
2723 "encoded length is longer than data",
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 = OctetString().decode(
2750 decode_path=sub_decode_path,
2756 "expected OctetString encoded chunk",
2757 klass=self.__class__,
2758 decode_path=sub_decode_path,
2761 chunks.append(chunk)
2762 sub_offset += chunk.tlvlen
2763 vlen += chunk.tlvlen
2766 obj = self.__class__(
2767 value=b"".join(bytes(chunk) for chunk in chunks),
2768 bounds=(self._bound_min, self._bound_max),
2771 default=self.default,
2772 optional=self.optional,
2773 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2775 except DecodeError as err:
2778 klass=self.__class__,
2779 decode_path=decode_path,
2782 except BoundsError as err:
2785 klass=self.__class__,
2786 decode_path=decode_path,
2789 obj.lenindef = lenindef
2790 obj.ber_encoded = True
2791 return obj, (v[EOC_LEN:] if lenindef else v)
2793 klass=self.__class__,
2794 decode_path=decode_path,
2799 return pp_console_row(next(self.pps()))
2801 def pps(self, decode_path=()):
2803 asn1_type_name=self.asn1_type_name,
2804 obj_name=self.__class__.__name__,
2805 decode_path=decode_path,
2806 value=("%d bytes" % len(self._value)) if self.ready else None,
2807 blob=self._value if self.ready else None,
2808 optional=self.optional,
2809 default=self == self.default,
2810 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2811 expl=None if self._expl is None else tag_decode(self._expl),
2816 expl_offset=self.expl_offset if self.expled else None,
2817 expl_tlen=self.expl_tlen if self.expled else None,
2818 expl_llen=self.expl_llen if self.expled else None,
2819 expl_vlen=self.expl_vlen if self.expled else None,
2820 expl_lenindef=self.expl_lenindef,
2821 lenindef=self.lenindef,
2822 ber_encoded=self.ber_encoded,
2825 defined_by, defined = self.defined or (None, None)
2826 if defined_by is not None:
2828 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2830 for pp in self.pps_lenindef(decode_path):
2835 """``NULL`` null object
2843 tag_default = tag_encode(5)
2844 asn1_type_name = "NULL"
2848 value=None, # unused, but Sequence passes it
2855 :param bytes impl: override default tag with ``IMPLICIT`` one
2856 :param bytes expl: override default tag with ``EXPLICIT`` one
2857 :param bool optional: is object ``OPTIONAL`` in sequence
2859 super(Null, self).__init__(impl, expl, None, optional, _decoded)
2867 obj = self.__class__()
2869 obj._expl = self._expl
2870 obj.default = self.default
2871 obj.optional = self.optional
2872 obj.offset = self.offset
2873 obj.llen = self.llen
2874 obj.vlen = self.vlen
2877 def __eq__(self, their):
2878 if not issubclass(their.__class__, Null):
2881 self.tag == their.tag and
2882 self._expl == their._expl
2892 return self.__class__(
2893 impl=self.tag if impl is None else impl,
2894 expl=self._expl if expl is None else expl,
2895 optional=self.optional if optional is None else optional,
2899 return self.tag + len_encode(0)
2901 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2903 t, _, lv = tag_strip(tlv)
2904 except DecodeError as err:
2905 raise err.__class__(
2907 klass=self.__class__,
2908 decode_path=decode_path,
2913 klass=self.__class__,
2914 decode_path=decode_path,
2917 if tag_only: # pragma: no cover
2920 l, _, v = len_decode(lv)
2921 except DecodeError as err:
2922 raise err.__class__(
2924 klass=self.__class__,
2925 decode_path=decode_path,
2929 raise InvalidLength(
2930 "Null must have zero length",
2931 klass=self.__class__,
2932 decode_path=decode_path,
2935 obj = self.__class__(
2938 optional=self.optional,
2939 _decoded=(offset, 1, 0),
2944 return pp_console_row(next(self.pps()))
2946 def pps(self, decode_path=()):
2948 asn1_type_name=self.asn1_type_name,
2949 obj_name=self.__class__.__name__,
2950 decode_path=decode_path,
2951 optional=self.optional,
2952 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2953 expl=None if self._expl is None else tag_decode(self._expl),
2958 expl_offset=self.expl_offset if self.expled else None,
2959 expl_tlen=self.expl_tlen if self.expled else None,
2960 expl_llen=self.expl_llen if self.expled else None,
2961 expl_vlen=self.expl_vlen if self.expled else None,
2962 expl_lenindef=self.expl_lenindef,
2965 for pp in self.pps_lenindef(decode_path):
2969 class ObjectIdentifier(Obj):
2970 """``OBJECT IDENTIFIER`` OID type
2972 >>> oid = ObjectIdentifier((1, 2, 3))
2973 OBJECT IDENTIFIER 1.2.3
2974 >>> oid == ObjectIdentifier("1.2.3")
2980 >>> oid + (4, 5) + ObjectIdentifier("1.7")
2981 OBJECT IDENTIFIER 1.2.3.4.5.1.7
2983 >>> str(ObjectIdentifier((3, 1)))
2984 Traceback (most recent call last):
2985 pyderasn.InvalidOID: unacceptable first arc value
2987 __slots__ = ("defines",)
2988 tag_default = tag_encode(6)
2989 asn1_type_name = "OBJECT IDENTIFIER"
3002 :param value: set the value. Either tuples of integers,
3003 string of "."-concatenated integers, or
3004 :py:class:`pyderasn.ObjectIdentifier` object
3005 :param defines: sequence of tuples. Each tuple has two elements.
3006 First one is relative to current one decode
3007 path, aiming to the field defined by that OID.
3008 Read about relative path in
3009 :py:func:`pyderasn.abs_decode_path`. Second
3010 tuple element is ``{OID: pyderasn.Obj()}``
3011 dictionary, mapping between current OID value
3012 and structure applied to defined field.
3013 :ref:`Read about DEFINED BY <definedby>`
3014 :param bytes impl: override default tag with ``IMPLICIT`` one
3015 :param bytes expl: override default tag with ``EXPLICIT`` one
3016 :param default: set default value. Type same as in ``value``
3017 :param bool optional: is object ``OPTIONAL`` in sequence
3019 super(ObjectIdentifier, self).__init__(
3027 if value is not None:
3028 self._value = self._value_sanitize(value)
3029 if default is not None:
3030 default = self._value_sanitize(default)
3031 self.default = self.__class__(
3036 if self._value is None:
3037 self._value = default
3038 self.defines = defines
3040 def __add__(self, their):
3041 if isinstance(their, self.__class__):
3042 return self.__class__(self._value + their._value)
3043 if isinstance(their, tuple):
3044 return self.__class__(self._value + their)
3045 raise InvalidValueType((self.__class__, tuple))
3047 def _value_sanitize(self, value):
3048 if issubclass(value.__class__, ObjectIdentifier):
3050 if isinstance(value, string_types):
3052 value = tuple(int(arc) for arc in value.split("."))
3054 raise InvalidOID("unacceptable arcs values")
3055 if isinstance(value, tuple):
3057 raise InvalidOID("less than 2 arcs")
3058 first_arc = value[0]
3059 if first_arc in (0, 1):
3060 if not (0 <= value[1] <= 39):
3061 raise InvalidOID("second arc is too wide")
3062 elif first_arc == 2:
3065 raise InvalidOID("unacceptable first arc value")
3067 raise InvalidValueType((self.__class__, str, tuple))
3071 return self._value is not None
3074 obj = self.__class__()
3075 obj._value = self._value
3076 obj.defines = self.defines
3078 obj._expl = self._expl
3079 obj.default = self.default
3080 obj.optional = self.optional
3081 obj.offset = self.offset
3082 obj.llen = self.llen
3083 obj.vlen = self.vlen
3087 self._assert_ready()
3088 return iter(self._value)
3091 return ".".join(str(arc) for arc in self._value or ())
3094 self._assert_ready()
3097 bytes(self._expl or b"") +
3098 str(self._value).encode("ascii"),
3101 def __eq__(self, their):
3102 if isinstance(their, tuple):
3103 return self._value == their
3104 if not issubclass(their.__class__, ObjectIdentifier):
3107 self.tag == their.tag and
3108 self._expl == their._expl and
3109 self._value == their._value
3112 def __lt__(self, their):
3113 return self._value < their._value
3124 return self.__class__(
3126 defines=self.defines if defines is None else defines,
3127 impl=self.tag if impl is None else impl,
3128 expl=self._expl if expl is None else expl,
3129 default=self.default if default is None else default,
3130 optional=self.optional if optional is None else optional,
3134 self._assert_ready()
3136 first_value = value[1]
3137 first_arc = value[0]
3140 elif first_arc == 1:
3142 elif first_arc == 2:
3144 else: # pragma: no cover
3145 raise RuntimeError("invalid arc is stored")
3146 octets = [zero_ended_encode(first_value)]
3147 for arc in value[2:]:
3148 octets.append(zero_ended_encode(arc))
3149 v = b"".join(octets)
3150 return b"".join((self.tag, len_encode(len(v)), v))
3152 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3154 t, _, lv = tag_strip(tlv)
3155 except DecodeError as err:
3156 raise err.__class__(
3158 klass=self.__class__,
3159 decode_path=decode_path,
3164 klass=self.__class__,
3165 decode_path=decode_path,
3168 if tag_only: # pragma: no cover
3171 l, llen, v = len_decode(lv)
3172 except DecodeError as err:
3173 raise err.__class__(
3175 klass=self.__class__,
3176 decode_path=decode_path,
3180 raise NotEnoughData(
3181 "encoded length is longer than data",
3182 klass=self.__class__,
3183 decode_path=decode_path,
3187 raise NotEnoughData(
3189 klass=self.__class__,
3190 decode_path=decode_path,
3193 v, tail = v[:l], v[l:]
3199 octet = indexbytes(v, i)
3200 arc = (arc << 7) | (octet & 0x7F)
3201 if octet & 0x80 == 0:
3209 klass=self.__class__,
3210 decode_path=decode_path,
3214 second_arc = arcs[0]
3215 if 0 <= second_arc <= 39:
3217 elif 40 <= second_arc <= 79:
3223 obj = self.__class__(
3224 value=tuple([first_arc, second_arc] + arcs[1:]),
3227 default=self.default,
3228 optional=self.optional,
3229 _decoded=(offset, llen, l),
3234 return pp_console_row(next(self.pps()))
3236 def pps(self, decode_path=()):
3238 asn1_type_name=self.asn1_type_name,
3239 obj_name=self.__class__.__name__,
3240 decode_path=decode_path,
3241 value=str(self) if self.ready else None,
3242 optional=self.optional,
3243 default=self == self.default,
3244 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3245 expl=None if self._expl is None else tag_decode(self._expl),
3250 expl_offset=self.expl_offset if self.expled else None,
3251 expl_tlen=self.expl_tlen if self.expled else None,
3252 expl_llen=self.expl_llen if self.expled else None,
3253 expl_vlen=self.expl_vlen if self.expled else None,
3254 expl_lenindef=self.expl_lenindef,
3257 for pp in self.pps_lenindef(decode_path):
3261 class Enumerated(Integer):
3262 """``ENUMERATED`` integer type
3264 This type is identical to :py:class:`pyderasn.Integer`, but requires
3265 schema to be specified and does not accept values missing from it.
3268 tag_default = tag_encode(10)
3269 asn1_type_name = "ENUMERATED"
3280 bounds=None, # dummy argument, workability for Integer.decode
3282 super(Enumerated, self).__init__(
3291 if len(self.specs) == 0:
3292 raise ValueError("schema must be specified")
3294 def _value_sanitize(self, value):
3295 if isinstance(value, self.__class__):
3296 value = value._value
3297 elif isinstance(value, integer_types):
3298 if value not in list(self.specs.values()):
3300 "unknown integer value: %s" % value,
3301 klass=self.__class__,
3303 elif isinstance(value, string_types):
3304 value = self.specs.get(value)
3306 raise ObjUnknown("integer value: %s" % value)
3308 raise InvalidValueType((self.__class__, int, str))
3312 obj = self.__class__(_specs=self.specs)
3313 obj._value = self._value
3314 obj._bound_min = self._bound_min
3315 obj._bound_max = self._bound_max
3317 obj._expl = self._expl
3318 obj.default = self.default
3319 obj.optional = self.optional
3320 obj.offset = self.offset
3321 obj.llen = self.llen
3322 obj.vlen = self.vlen
3334 return self.__class__(
3336 impl=self.tag if impl is None else impl,
3337 expl=self._expl if expl is None else expl,
3338 default=self.default if default is None else default,
3339 optional=self.optional if optional is None else optional,
3344 class CommonString(OctetString):
3345 """Common class for all strings
3347 Everything resembles :py:class:`pyderasn.OctetString`, except
3348 ability to deal with unicode text strings.
3350 >>> hexenc("привет мир".encode("utf-8"))
3351 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3352 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3354 >>> s = UTF8String("привет мир")
3355 UTF8String UTF8String привет мир
3357 'привет мир'
3358 >>> hexenc(bytes(s))
3359 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3361 >>> PrintableString("привет мир")
3362 Traceback (most recent call last):
3363 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3365 >>> BMPString("ада", bounds=(2, 2))
3366 Traceback (most recent call last):
3367 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3368 >>> s = BMPString("ад", bounds=(2, 2))
3371 >>> hexenc(bytes(s))
3379 * - :py:class:`pyderasn.UTF8String`
3381 * - :py:class:`pyderasn.NumericString`
3383 * - :py:class:`pyderasn.PrintableString`
3385 * - :py:class:`pyderasn.TeletexString`
3387 * - :py:class:`pyderasn.T61String`
3389 * - :py:class:`pyderasn.VideotexString`
3391 * - :py:class:`pyderasn.IA5String`
3393 * - :py:class:`pyderasn.GraphicString`
3395 * - :py:class:`pyderasn.VisibleString`
3397 * - :py:class:`pyderasn.ISO646String`
3399 * - :py:class:`pyderasn.GeneralString`
3401 * - :py:class:`pyderasn.UniversalString`
3403 * - :py:class:`pyderasn.BMPString`
3406 __slots__ = ("encoding",)
3408 def _value_sanitize(self, value):
3410 value_decoded = None
3411 if isinstance(value, self.__class__):
3412 value_raw = value._value
3413 elif isinstance(value, text_type):
3414 value_decoded = value
3415 elif isinstance(value, binary_type):
3418 raise InvalidValueType((self.__class__, text_type, binary_type))
3421 value_decoded.encode(self.encoding)
3422 if value_raw is None else value_raw
3425 value_raw.decode(self.encoding)
3426 if value_decoded is None else value_decoded
3428 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3429 raise DecodeError(str(err))
3430 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3438 def __eq__(self, their):
3439 if isinstance(their, binary_type):
3440 return self._value == their
3441 if isinstance(their, text_type):
3442 return self._value == their.encode(self.encoding)
3443 if not isinstance(their, self.__class__):
3446 self._value == their._value and
3447 self.tag == their.tag and
3448 self._expl == their._expl
3451 def __unicode__(self):
3453 return self._value.decode(self.encoding)
3454 return text_type(self._value)
3457 return pp_console_row(next(self.pps(no_unicode=PY2)))
3459 def pps(self, decode_path=(), no_unicode=False):
3462 value = hexenc(bytes(self)) if no_unicode else self.__unicode__()
3464 asn1_type_name=self.asn1_type_name,
3465 obj_name=self.__class__.__name__,
3466 decode_path=decode_path,
3468 optional=self.optional,
3469 default=self == self.default,
3470 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3471 expl=None if self._expl is None else tag_decode(self._expl),
3476 expl_offset=self.expl_offset if self.expled else None,
3477 expl_tlen=self.expl_tlen if self.expled else None,
3478 expl_llen=self.expl_llen if self.expled else None,
3479 expl_vlen=self.expl_vlen if self.expled else None,
3480 expl_lenindef=self.expl_lenindef,
3481 ber_encoded=self.ber_encoded,
3484 for pp in self.pps_lenindef(decode_path):
3488 class UTF8String(CommonString):
3490 tag_default = tag_encode(12)
3492 asn1_type_name = "UTF8String"
3495 class NumericString(CommonString):
3498 Its value is properly sanitized: only ASCII digits with spaces can
3502 tag_default = tag_encode(18)
3504 asn1_type_name = "NumericString"
3505 allowable_chars = set(digits.encode("ascii") + b" ")
3507 def _value_sanitize(self, value):
3508 value = super(NumericString, self)._value_sanitize(value)
3509 if not set(value) <= self.allowable_chars:
3510 raise DecodeError("non-numeric value")
3514 class PrintableString(CommonString):
3517 Its value is properly sanitized: see X.680 41.4 table 10.
3520 tag_default = tag_encode(19)
3522 asn1_type_name = "PrintableString"
3523 allowable_chars = set((ascii_letters + digits + " '()+,-./:=?").encode("ascii"))
3525 def _value_sanitize(self, value):
3526 value = super(PrintableString, self)._value_sanitize(value)
3527 if not set(value) <= self.allowable_chars:
3528 raise DecodeError("non-printable value")
3532 class TeletexString(CommonString):
3534 tag_default = tag_encode(20)
3536 asn1_type_name = "TeletexString"
3539 class T61String(TeletexString):
3541 asn1_type_name = "T61String"
3544 class VideotexString(CommonString):
3546 tag_default = tag_encode(21)
3547 encoding = "iso-8859-1"
3548 asn1_type_name = "VideotexString"
3551 class IA5String(CommonString):
3553 tag_default = tag_encode(22)
3555 asn1_type_name = "IA5"
3558 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
3559 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
3560 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
3563 class UTCTime(CommonString):
3564 """``UTCTime`` datetime type
3566 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3567 UTCTime UTCTime 2017-09-30T22:07:50
3573 datetime.datetime(2017, 9, 30, 22, 7, 50)
3574 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
3575 datetime.datetime(1957, 9, 30, 22, 7, 50)
3578 tag_default = tag_encode(23)
3580 asn1_type_name = "UTCTime"
3582 fmt = "%y%m%d%H%M%SZ"
3592 bounds=None, # dummy argument, workability for OctetString.decode
3595 :param value: set the value. Either datetime type, or
3596 :py:class:`pyderasn.UTCTime` object
3597 :param bytes impl: override default tag with ``IMPLICIT`` one
3598 :param bytes expl: override default tag with ``EXPLICIT`` one
3599 :param default: set default value. Type same as in ``value``
3600 :param bool optional: is object ``OPTIONAL`` in sequence
3602 super(UTCTime, self).__init__(
3610 if value is not None:
3611 self._value = self._value_sanitize(value)
3612 if default is not None:
3613 default = self._value_sanitize(default)
3614 self.default = self.__class__(
3619 if self._value is None:
3620 self._value = default
3622 def _value_sanitize(self, value):
3623 if isinstance(value, self.__class__):
3625 if isinstance(value, datetime):
3626 return value.strftime(self.fmt).encode("ascii")
3627 if isinstance(value, binary_type):
3629 value_decoded = value.decode("ascii")
3630 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3631 raise DecodeError("invalid UTCTime encoding")
3632 if len(value_decoded) == LEN_YYMMDDHHMMSSZ:
3634 datetime.strptime(value_decoded, self.fmt)
3635 except (TypeError, ValueError):
3636 raise DecodeError("invalid UTCTime format")
3639 raise DecodeError("invalid UTCTime length")
3640 raise InvalidValueType((self.__class__, datetime))
3642 def __eq__(self, their):
3643 if isinstance(their, binary_type):
3644 return self._value == their
3645 if isinstance(their, datetime):
3646 return self.todatetime() == their
3647 if not isinstance(their, self.__class__):
3650 self._value == their._value and
3651 self.tag == their.tag and
3652 self._expl == their._expl
3655 def todatetime(self):
3656 """Convert to datetime
3660 Pay attention that UTCTime can not hold full year, so all years
3661 having < 50 years are treated as 20xx, 19xx otherwise, according
3662 to X.509 recomendation.
3664 value = datetime.strptime(self._value.decode("ascii"), self.fmt)
3665 year = value.year % 100
3667 year=(2000 + year) if year < 50 else (1900 + year),
3671 minute=value.minute,
3672 second=value.second,
3676 return pp_console_row(next(self.pps()))
3678 def pps(self, decode_path=()):
3680 asn1_type_name=self.asn1_type_name,
3681 obj_name=self.__class__.__name__,
3682 decode_path=decode_path,
3683 value=self.todatetime().isoformat() if self.ready else None,
3684 optional=self.optional,
3685 default=self == self.default,
3686 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3687 expl=None if self._expl is None else tag_decode(self._expl),
3692 expl_offset=self.expl_offset if self.expled else None,
3693 expl_tlen=self.expl_tlen if self.expled else None,
3694 expl_llen=self.expl_llen if self.expled else None,
3695 expl_vlen=self.expl_vlen if self.expled else None,
3696 expl_lenindef=self.expl_lenindef,
3697 ber_encoded=self.ber_encoded,
3700 for pp in self.pps_lenindef(decode_path):
3704 class GeneralizedTime(UTCTime):
3705 """``GeneralizedTime`` datetime type
3707 This type is similar to :py:class:`pyderasn.UTCTime`.
3709 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3710 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
3712 '20170930220750.000123Z'
3713 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
3714 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
3717 tag_default = tag_encode(24)
3718 asn1_type_name = "GeneralizedTime"
3720 fmt = "%Y%m%d%H%M%SZ"
3721 fmt_ms = "%Y%m%d%H%M%S.%fZ"
3723 def _value_sanitize(self, value):
3724 if isinstance(value, self.__class__):
3726 if isinstance(value, datetime):
3727 return value.strftime(
3728 self.fmt_ms if value.microsecond > 0 else self.fmt
3730 if isinstance(value, binary_type):
3732 value_decoded = value.decode("ascii")
3733 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3734 raise DecodeError("invalid GeneralizedTime encoding")
3735 if len(value_decoded) == LEN_YYYYMMDDHHMMSSZ:
3737 datetime.strptime(value_decoded, self.fmt)
3738 except (TypeError, ValueError):
3740 "invalid GeneralizedTime (without ms) format",
3743 elif len(value_decoded) >= LEN_YYYYMMDDHHMMSSDMZ:
3745 datetime.strptime(value_decoded, self.fmt_ms)
3746 except (TypeError, ValueError):
3748 "invalid GeneralizedTime (with ms) format",
3753 "invalid GeneralizedTime length",
3754 klass=self.__class__,
3756 raise InvalidValueType((self.__class__, datetime))
3758 def todatetime(self):
3759 value = self._value.decode("ascii")
3760 if len(value) == LEN_YYYYMMDDHHMMSSZ:
3761 return datetime.strptime(value, self.fmt)
3762 return datetime.strptime(value, self.fmt_ms)
3765 class GraphicString(CommonString):
3767 tag_default = tag_encode(25)
3768 encoding = "iso-8859-1"
3769 asn1_type_name = "GraphicString"
3772 class VisibleString(CommonString):
3774 tag_default = tag_encode(26)
3776 asn1_type_name = "VisibleString"
3779 class ISO646String(VisibleString):
3781 asn1_type_name = "ISO646String"
3784 class GeneralString(CommonString):
3786 tag_default = tag_encode(27)
3787 encoding = "iso-8859-1"
3788 asn1_type_name = "GeneralString"
3791 class UniversalString(CommonString):
3793 tag_default = tag_encode(28)
3794 encoding = "utf-32-be"
3795 asn1_type_name = "UniversalString"
3798 class BMPString(CommonString):
3800 tag_default = tag_encode(30)
3801 encoding = "utf-16-be"
3802 asn1_type_name = "BMPString"
3806 """``CHOICE`` special type
3810 class GeneralName(Choice):
3812 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
3813 ("dNSName", IA5String(impl=tag_ctxp(2))),
3816 >>> gn = GeneralName()
3818 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
3819 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3820 >>> gn["dNSName"] = IA5String("bar.baz")
3821 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
3822 >>> gn["rfc822Name"]
3825 [2] IA5String IA5 bar.baz
3828 >>> gn.value == gn["dNSName"]
3831 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
3833 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
3834 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3836 __slots__ = ("specs",)
3838 asn1_type_name = "CHOICE"
3851 :param value: set the value. Either ``(choice, value)`` tuple, or
3852 :py:class:`pyderasn.Choice` object
3853 :param bytes impl: can not be set, do **not** use it
3854 :param bytes expl: override default tag with ``EXPLICIT`` one
3855 :param default: set default value. Type same as in ``value``
3856 :param bool optional: is object ``OPTIONAL`` in sequence
3858 if impl is not None:
3859 raise ValueError("no implicit tag allowed for CHOICE")
3860 super(Choice, self).__init__(None, expl, default, optional, _decoded)
3862 schema = getattr(self, "schema", ())
3863 if len(schema) == 0:
3864 raise ValueError("schema must be specified")
3866 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
3869 if value is not None:
3870 self._value = self._value_sanitize(value)
3871 if default is not None:
3872 default_value = self._value_sanitize(default)
3873 default_obj = self.__class__(impl=self.tag, expl=self._expl)
3874 default_obj.specs = self.specs
3875 default_obj._value = default_value
3876 self.default = default_obj
3878 self._value = default_obj.copy()._value
3880 def _value_sanitize(self, value):
3881 if isinstance(value, self.__class__):
3883 if isinstance(value, tuple) and len(value) == 2:
3885 spec = self.specs.get(choice)
3887 raise ObjUnknown(choice)
3888 if not isinstance(obj, spec.__class__):
3889 raise InvalidValueType((spec,))
3890 return (choice, spec(obj))
3891 raise InvalidValueType((self.__class__, tuple))
3895 return self._value is not None and self._value[1].ready
3899 return self.expl_lenindef or (
3900 (self._value is not None) and
3901 self._value[1].bered
3905 obj = self.__class__(schema=self.specs)
3906 obj._expl = self._expl
3907 obj.default = self.default
3908 obj.optional = self.optional
3909 obj.offset = self.offset
3910 obj.llen = self.llen
3911 obj.vlen = self.vlen
3913 if value is not None:
3914 obj._value = (value[0], value[1].copy())
3917 def __eq__(self, their):
3918 if isinstance(their, tuple) and len(their) == 2:
3919 return self._value == their
3920 if not isinstance(their, self.__class__):
3923 self.specs == their.specs and
3924 self._value == their._value
3934 return self.__class__(
3937 expl=self._expl if expl is None else expl,
3938 default=self.default if default is None else default,
3939 optional=self.optional if optional is None else optional,
3944 self._assert_ready()
3945 return self._value[0]
3949 self._assert_ready()
3950 return self._value[1]
3952 def __getitem__(self, key):
3953 if key not in self.specs:
3954 raise ObjUnknown(key)
3955 if self._value is None:
3957 choice, value = self._value
3962 def __setitem__(self, key, value):
3963 spec = self.specs.get(key)
3965 raise ObjUnknown(key)
3966 if not isinstance(value, spec.__class__):
3967 raise InvalidValueType((spec.__class__,))
3968 self._value = (key, spec(value))
3976 return self._value[1].decoded if self.ready else False
3979 self._assert_ready()
3980 return self._value[1].encode()
3982 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3983 for choice, spec in self.specs.items():
3984 sub_decode_path = decode_path + (choice,)
3990 decode_path=sub_decode_path,
3999 klass=self.__class__,
4000 decode_path=decode_path,
4003 if tag_only: # pragma: no cover
4005 value, tail = spec.decode(
4009 decode_path=sub_decode_path,
4012 obj = self.__class__(
4015 default=self.default,
4016 optional=self.optional,
4017 _decoded=(offset, 0, value.fulllen),
4019 obj._value = (choice, value)
4023 value = pp_console_row(next(self.pps()))
4025 value = "%s[%r]" % (value, self.value)
4028 def pps(self, decode_path=()):
4030 asn1_type_name=self.asn1_type_name,
4031 obj_name=self.__class__.__name__,
4032 decode_path=decode_path,
4033 value=self.choice if self.ready else None,
4034 optional=self.optional,
4035 default=self == self.default,
4036 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4037 expl=None if self._expl is None else tag_decode(self._expl),
4042 expl_lenindef=self.expl_lenindef,
4046 yield self.value.pps(decode_path=decode_path + (self.choice,))
4047 for pp in self.pps_lenindef(decode_path):
4051 class PrimitiveTypes(Choice):
4052 """Predefined ``CHOICE`` for all generic primitive types
4054 It could be useful for general decoding of some unspecified values:
4056 >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
4057 OCTET STRING 3 bytes 666f6f
4058 >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
4062 schema = tuple((klass.__name__, klass()) for klass in (
4087 """``ANY`` special type
4089 >>> Any(Integer(-123))
4091 >>> a = Any(OctetString(b"hello world").encode())
4092 ANY 040b68656c6c6f20776f726c64
4093 >>> hexenc(bytes(a))
4094 b'0x040x0bhello world'
4096 __slots__ = ("defined",)
4097 tag_default = tag_encode(0)
4098 asn1_type_name = "ANY"
4108 :param value: set the value. Either any kind of pyderasn's
4109 **ready** object, or bytes. Pay attention that
4110 **no** validation is performed is raw binary value
4112 :param bytes expl: override default tag with ``EXPLICIT`` one
4113 :param bool optional: is object ``OPTIONAL`` in sequence
4115 super(Any, self).__init__(None, expl, None, optional, _decoded)
4116 self._value = None if value is None else self._value_sanitize(value)
4119 def _value_sanitize(self, value):
4120 if isinstance(value, self.__class__):
4122 if isinstance(value, Obj):
4123 return value.encode()
4124 if isinstance(value, binary_type):
4126 raise InvalidValueType((self.__class__, Obj, binary_type))
4130 return self._value is not None
4134 if self.expl_lenindef or self.lenindef:
4136 if self.defined is None:
4138 return self.defined[1].bered
4141 obj = self.__class__()
4142 obj._value = self._value
4144 obj._expl = self._expl
4145 obj.optional = self.optional
4146 obj.offset = self.offset
4147 obj.llen = self.llen
4148 obj.vlen = self.vlen
4151 def __eq__(self, their):
4152 if isinstance(their, binary_type):
4153 return self._value == their
4154 if issubclass(their.__class__, Any):
4155 return self._value == their._value
4164 return self.__class__(
4166 expl=self._expl if expl is None else expl,
4167 optional=self.optional if optional is None else optional,
4170 def __bytes__(self):
4171 self._assert_ready()
4179 self._assert_ready()
4182 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4184 t, tlen, lv = tag_strip(tlv)
4185 except DecodeError as err:
4186 raise err.__class__(
4188 klass=self.__class__,
4189 decode_path=decode_path,
4193 l, llen, v = len_decode(lv)
4194 except LenIndefForm as err:
4195 if not ctx.get("bered", False):
4196 raise err.__class__(
4198 klass=self.__class__,
4199 decode_path=decode_path,
4202 llen, vlen, v = 1, 0, lv[1:]
4203 sub_offset = offset + tlen + llen
4205 while v[:EOC_LEN].tobytes() != EOC:
4206 chunk, v = Any().decode(
4209 decode_path=decode_path + (str(chunk_i),),
4213 vlen += chunk.tlvlen
4214 sub_offset += chunk.tlvlen
4216 tlvlen = tlen + llen + vlen + EOC_LEN
4217 obj = self.__class__(
4218 value=tlv[:tlvlen].tobytes(),
4220 optional=self.optional,
4221 _decoded=(offset, 0, tlvlen),
4225 return obj, v[EOC_LEN:]
4226 except DecodeError as err:
4227 raise err.__class__(
4229 klass=self.__class__,
4230 decode_path=decode_path,
4234 raise NotEnoughData(
4235 "encoded length is longer than data",
4236 klass=self.__class__,
4237 decode_path=decode_path,
4240 tlvlen = tlen + llen + l
4241 v, tail = tlv[:tlvlen], v[l:]
4242 obj = self.__class__(
4245 optional=self.optional,
4246 _decoded=(offset, 0, tlvlen),
4252 return pp_console_row(next(self.pps()))
4254 def pps(self, decode_path=()):
4256 asn1_type_name=self.asn1_type_name,
4257 obj_name=self.__class__.__name__,
4258 decode_path=decode_path,
4259 blob=self._value if self.ready else None,
4260 optional=self.optional,
4261 default=self == self.default,
4262 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4263 expl=None if self._expl is None else tag_decode(self._expl),
4268 expl_offset=self.expl_offset if self.expled else None,
4269 expl_tlen=self.expl_tlen if self.expled else None,
4270 expl_llen=self.expl_llen if self.expled else None,
4271 expl_vlen=self.expl_vlen if self.expled else None,
4272 expl_lenindef=self.expl_lenindef,
4273 lenindef=self.lenindef,
4276 defined_by, defined = self.defined or (None, None)
4277 if defined_by is not None:
4279 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4281 for pp in self.pps_lenindef(decode_path):
4285 ########################################################################
4286 # ASN.1 constructed types
4287 ########################################################################
4289 def get_def_by_path(defines_by_path, sub_decode_path):
4290 """Get define by decode path
4292 for path, define in defines_by_path:
4293 if len(path) != len(sub_decode_path):
4295 for p1, p2 in zip(path, sub_decode_path):
4296 if (p1 != any) and (p1 != p2):
4302 def abs_decode_path(decode_path, rel_path):
4303 """Create an absolute decode path from current and relative ones
4305 :param decode_path: current decode path, starting point.
4307 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4308 If first tuple's element is "/", then treat it as
4309 an absolute path, ignoring ``decode_path`` as
4310 starting point. Also this tuple can contain ".."
4311 elements, stripping the leading element from
4314 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4315 ("foo", "bar", "baz", "whatever")
4316 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4318 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4321 if rel_path[0] == "/":
4323 if rel_path[0] == "..":
4324 return abs_decode_path(decode_path[:-1], rel_path[1:])
4325 return decode_path + rel_path
4328 class Sequence(Obj):
4329 """``SEQUENCE`` structure type
4331 You have to make specification of sequence::
4333 class Extension(Sequence):
4335 ("extnID", ObjectIdentifier()),
4336 ("critical", Boolean(default=False)),
4337 ("extnValue", OctetString()),
4340 Then, you can work with it as with dictionary.
4342 >>> ext = Extension()
4343 >>> Extension().specs
4345 ('extnID', OBJECT IDENTIFIER),
4346 ('critical', BOOLEAN False OPTIONAL DEFAULT),
4347 ('extnValue', OCTET STRING),
4349 >>> ext["extnID"] = "1.2.3"
4350 Traceback (most recent call last):
4351 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
4352 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
4354 You can determine if sequence is ready to be encoded:
4359 Traceback (most recent call last):
4360 pyderasn.ObjNotReady: object is not ready: extnValue
4361 >>> ext["extnValue"] = OctetString(b"foobar")
4365 Value you want to assign, must have the same **type** as in
4366 corresponding specification, but it can have different tags,
4367 optional/default attributes -- they will be taken from specification
4370 class TBSCertificate(Sequence):
4372 ("version", Version(expl=tag_ctxc(0), default="v1")),
4375 >>> tbs = TBSCertificate()
4376 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
4378 Assign ``None`` to remove value from sequence.
4380 You can set values in Sequence during its initialization:
4382 >>> AlgorithmIdentifier((
4383 ("algorithm", ObjectIdentifier("1.2.3")),
4384 ("parameters", Any(Null()))
4386 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
4388 You can determine if value exists/set in the sequence and take its value:
4390 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
4393 OBJECT IDENTIFIER 1.2.3
4395 But pay attention that if value has default, then it won't be (not
4396 in) in the sequence (because ``DEFAULT`` must not be encoded in
4397 DER), but you can read its value:
4399 >>> "critical" in ext, ext["critical"]
4400 (False, BOOLEAN False)
4401 >>> ext["critical"] = Boolean(True)
4402 >>> "critical" in ext, ext["critical"]
4403 (True, BOOLEAN True)
4405 All defaulted values are always optional.
4407 .. _allow_default_values_ctx:
4409 DER prohibits default value encoding and will raise an error if
4410 default value is unexpectedly met during decode.
4411 If :ref:`bered <bered_ctx>` context option is set, then no error
4412 will be raised, but ``bered`` attribute set. You can disable strict
4413 defaulted values existence validation by setting
4414 ``"allow_default_values": True`` :ref:`context <ctx>` option.
4416 Two sequences are equal if they have equal specification (schema),
4417 implicit/explicit tagging and the same values.
4419 __slots__ = ("specs",)
4420 tag_default = tag_encode(form=TagFormConstructed, num=16)
4421 asn1_type_name = "SEQUENCE"
4433 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
4435 schema = getattr(self, "schema", ())
4437 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4440 if value is not None:
4441 if issubclass(value.__class__, Sequence):
4442 self._value = value._value
4443 elif hasattr(value, "__iter__"):
4444 for seq_key, seq_value in value:
4445 self[seq_key] = seq_value
4447 raise InvalidValueType((Sequence,))
4448 if default is not None:
4449 if not issubclass(default.__class__, Sequence):
4450 raise InvalidValueType((Sequence,))
4451 default_value = default._value
4452 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4453 default_obj.specs = self.specs
4454 default_obj._value = default_value
4455 self.default = default_obj
4457 self._value = default_obj.copy()._value
4461 for name, spec in self.specs.items():
4462 value = self._value.get(name)
4474 if self.expl_lenindef or self.lenindef or self.ber_encoded:
4476 return any(value.bered for value in self._value.values())
4479 obj = self.__class__(schema=self.specs)
4481 obj._expl = self._expl
4482 obj.default = self.default
4483 obj.optional = self.optional
4484 obj.offset = self.offset
4485 obj.llen = self.llen
4486 obj.vlen = self.vlen
4487 obj._value = {k: v.copy() for k, v in self._value.items()}
4490 def __eq__(self, their):
4491 if not isinstance(their, self.__class__):
4494 self.specs == their.specs and
4495 self.tag == their.tag and
4496 self._expl == their._expl and
4497 self._value == their._value
4508 return self.__class__(
4511 impl=self.tag if impl is None else impl,
4512 expl=self._expl if expl is None else expl,
4513 default=self.default if default is None else default,
4514 optional=self.optional if optional is None else optional,
4517 def __contains__(self, key):
4518 return key in self._value
4520 def __setitem__(self, key, value):
4521 spec = self.specs.get(key)
4523 raise ObjUnknown(key)
4525 self._value.pop(key, None)
4527 if not isinstance(value, spec.__class__):
4528 raise InvalidValueType((spec.__class__,))
4529 value = spec(value=value)
4530 if spec.default is not None and value == spec.default:
4531 self._value.pop(key, None)
4533 self._value[key] = value
4535 def __getitem__(self, key):
4536 value = self._value.get(key)
4537 if value is not None:
4539 spec = self.specs.get(key)
4541 raise ObjUnknown(key)
4542 if spec.default is not None:
4546 def _encoded_values(self):
4548 for name, spec in self.specs.items():
4549 value = self._value.get(name)
4553 raise ObjNotReady(name)
4554 raws.append(value.encode())
4558 v = b"".join(self._encoded_values())
4559 return b"".join((self.tag, len_encode(len(v)), v))
4561 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4563 t, tlen, lv = tag_strip(tlv)
4564 except DecodeError as err:
4565 raise err.__class__(
4567 klass=self.__class__,
4568 decode_path=decode_path,
4573 klass=self.__class__,
4574 decode_path=decode_path,
4577 if tag_only: # pragma: no cover
4580 ctx_bered = ctx.get("bered", False)
4582 l, llen, v = len_decode(lv)
4583 except LenIndefForm as err:
4585 raise err.__class__(
4587 klass=self.__class__,
4588 decode_path=decode_path,
4591 l, llen, v = 0, 1, lv[1:]
4593 except DecodeError as err:
4594 raise err.__class__(
4596 klass=self.__class__,
4597 decode_path=decode_path,
4601 raise NotEnoughData(
4602 "encoded length is longer than data",
4603 klass=self.__class__,
4604 decode_path=decode_path,
4608 v, tail = v[:l], v[l:]
4610 sub_offset = offset + tlen + llen
4613 ctx_allow_default_values = ctx.get("allow_default_values", False)
4614 for name, spec in self.specs.items():
4615 if spec.optional and (
4616 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
4620 sub_decode_path = decode_path + (name,)
4622 value, v_tail = spec.decode(
4626 decode_path=sub_decode_path,
4634 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
4635 if defined is not None:
4636 defined_by, defined_spec = defined
4637 if issubclass(value.__class__, SequenceOf):
4638 for i, _value in enumerate(value):
4639 sub_sub_decode_path = sub_decode_path + (
4641 DecodePathDefBy(defined_by),
4643 defined_value, defined_tail = defined_spec.decode(
4644 memoryview(bytes(_value)),
4646 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4647 if value.expled else (value.tlen + value.llen)
4650 decode_path=sub_sub_decode_path,
4653 if len(defined_tail) > 0:
4656 klass=self.__class__,
4657 decode_path=sub_sub_decode_path,
4660 _value.defined = (defined_by, defined_value)
4662 defined_value, defined_tail = defined_spec.decode(
4663 memoryview(bytes(value)),
4665 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4666 if value.expled else (value.tlen + value.llen)
4669 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4672 if len(defined_tail) > 0:
4675 klass=self.__class__,
4676 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4679 value.defined = (defined_by, defined_value)
4681 value_len = value.fulllen
4683 sub_offset += value_len
4685 if spec.default is not None and value == spec.default:
4686 if ctx_bered or ctx_allow_default_values:
4690 "DEFAULT value met",
4691 klass=self.__class__,
4692 decode_path=sub_decode_path,
4695 values[name] = value
4697 spec_defines = getattr(spec, "defines", ())
4698 if len(spec_defines) == 0:
4699 defines_by_path = ctx.get("defines_by_path", ())
4700 if len(defines_by_path) > 0:
4701 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
4702 if spec_defines is not None and len(spec_defines) > 0:
4703 for rel_path, schema in spec_defines:
4704 defined = schema.get(value, None)
4705 if defined is not None:
4706 ctx.setdefault("_defines", []).append((
4707 abs_decode_path(sub_decode_path[:-1], rel_path),
4711 if v[:EOC_LEN].tobytes() != EOC:
4714 klass=self.__class__,
4715 decode_path=decode_path,
4723 klass=self.__class__,
4724 decode_path=decode_path,
4727 obj = self.__class__(
4731 default=self.default,
4732 optional=self.optional,
4733 _decoded=(offset, llen, vlen),
4736 obj.lenindef = lenindef
4737 obj.ber_encoded = ber_encoded
4741 value = pp_console_row(next(self.pps()))
4743 for name in self.specs:
4744 _value = self._value.get(name)
4747 cols.append("%s: %s" % (name, repr(_value)))
4748 return "%s[%s]" % (value, "; ".join(cols))
4750 def pps(self, decode_path=()):
4752 asn1_type_name=self.asn1_type_name,
4753 obj_name=self.__class__.__name__,
4754 decode_path=decode_path,
4755 optional=self.optional,
4756 default=self == self.default,
4757 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4758 expl=None if self._expl is None else tag_decode(self._expl),
4763 expl_offset=self.expl_offset if self.expled else None,
4764 expl_tlen=self.expl_tlen if self.expled else None,
4765 expl_llen=self.expl_llen if self.expled else None,
4766 expl_vlen=self.expl_vlen if self.expled else None,
4767 expl_lenindef=self.expl_lenindef,
4768 lenindef=self.lenindef,
4769 ber_encoded=self.ber_encoded,
4772 for name in self.specs:
4773 value = self._value.get(name)
4776 yield value.pps(decode_path=decode_path + (name,))
4777 for pp in self.pps_lenindef(decode_path):
4781 class Set(Sequence):
4782 """``SET`` structure type
4784 Its usage is identical to :py:class:`pyderasn.Sequence`.
4786 .. _allow_unordered_set_ctx:
4788 DER prohibits unordered values encoding and will raise an error
4789 during decode. If If :ref:`bered <bered_ctx>` context option is set,
4790 then no error will occure. Also you can disable strict values
4791 ordering check by setting ``"allow_unordered_set": True``
4792 :ref:`context <ctx>` option.
4795 tag_default = tag_encode(form=TagFormConstructed, num=17)
4796 asn1_type_name = "SET"
4799 raws = self._encoded_values()
4802 return b"".join((self.tag, len_encode(len(v)), v))
4804 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4806 t, tlen, lv = tag_strip(tlv)
4807 except DecodeError as err:
4808 raise err.__class__(
4810 klass=self.__class__,
4811 decode_path=decode_path,
4816 klass=self.__class__,
4817 decode_path=decode_path,
4823 ctx_bered = ctx.get("bered", False)
4825 l, llen, v = len_decode(lv)
4826 except LenIndefForm as err:
4828 raise err.__class__(
4830 klass=self.__class__,
4831 decode_path=decode_path,
4834 l, llen, v = 0, 1, lv[1:]
4836 except DecodeError as err:
4837 raise err.__class__(
4839 klass=self.__class__,
4840 decode_path=decode_path,
4844 raise NotEnoughData(
4845 "encoded length is longer than data",
4846 klass=self.__class__,
4850 v, tail = v[:l], v[l:]
4852 sub_offset = offset + tlen + llen
4855 ctx_allow_default_values = ctx.get("allow_default_values", False)
4856 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
4857 value_prev = memoryview(v[:0])
4858 specs_items = self.specs.items
4860 if lenindef and v[:EOC_LEN].tobytes() == EOC:
4862 for name, spec in specs_items():
4863 sub_decode_path = decode_path + (name,)
4869 decode_path=sub_decode_path,
4878 klass=self.__class__,
4879 decode_path=decode_path,
4882 value, v_tail = spec.decode(
4886 decode_path=sub_decode_path,
4889 value_len = value.fulllen
4890 if value_prev.tobytes() > v[:value_len].tobytes():
4891 if ctx_bered or ctx_allow_unordered_set:
4895 "unordered " + self.asn1_type_name,
4896 klass=self.__class__,
4897 decode_path=sub_decode_path,
4900 if spec.default is None or value != spec.default:
4902 elif ctx_bered or ctx_allow_default_values:
4906 "DEFAULT value met",
4907 klass=self.__class__,
4908 decode_path=sub_decode_path,
4911 values[name] = value
4912 value_prev = v[:value_len]
4913 sub_offset += value_len
4916 obj = self.__class__(
4920 default=self.default,
4921 optional=self.optional,
4922 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
4925 if v[:EOC_LEN].tobytes() != EOC:
4928 klass=self.__class__,
4929 decode_path=decode_path,
4937 "not all values are ready",
4938 klass=self.__class__,
4939 decode_path=decode_path,
4942 obj.ber_encoded = ber_encoded
4946 class SequenceOf(Obj):
4947 """``SEQUENCE OF`` sequence type
4949 For that kind of type you must specify the object it will carry on
4950 (bounds are for example here, not required)::
4952 class Ints(SequenceOf):
4957 >>> ints.append(Integer(123))
4958 >>> ints.append(Integer(234))
4960 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
4961 >>> [int(i) for i in ints]
4963 >>> ints.append(Integer(345))
4964 Traceback (most recent call last):
4965 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
4968 >>> ints[1] = Integer(345)
4970 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
4972 Also you can initialize sequence with preinitialized values:
4974 >>> ints = Ints([Integer(123), Integer(234)])
4976 __slots__ = ("spec", "_bound_min", "_bound_max")
4977 tag_default = tag_encode(form=TagFormConstructed, num=16)
4978 asn1_type_name = "SEQUENCE OF"
4991 super(SequenceOf, self).__init__(
4999 schema = getattr(self, "schema", None)
5001 raise ValueError("schema must be specified")
5003 self._bound_min, self._bound_max = getattr(
5007 ) if bounds is None else bounds
5009 if value is not None:
5010 self._value = self._value_sanitize(value)
5011 if default is not None:
5012 default_value = self._value_sanitize(default)
5013 default_obj = self.__class__(
5018 default_obj._value = default_value
5019 self.default = default_obj
5021 self._value = default_obj.copy()._value
5023 def _value_sanitize(self, value):
5024 if issubclass(value.__class__, SequenceOf):
5025 value = value._value
5026 elif hasattr(value, "__iter__"):
5029 raise InvalidValueType((self.__class__, iter))
5030 if not self._bound_min <= len(value) <= self._bound_max:
5031 raise BoundsError(self._bound_min, len(value), self._bound_max)
5033 if not isinstance(v, self.spec.__class__):
5034 raise InvalidValueType((self.spec.__class__,))
5039 return all(v.ready for v in self._value)
5043 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5045 return any(v.bered for v in self._value)
5048 obj = self.__class__(schema=self.spec)
5049 obj._bound_min = self._bound_min
5050 obj._bound_max = self._bound_max
5052 obj._expl = self._expl
5053 obj.default = self.default
5054 obj.optional = self.optional
5055 obj.offset = self.offset
5056 obj.llen = self.llen
5057 obj.vlen = self.vlen
5058 obj._value = [v.copy() for v in self._value]
5061 def __eq__(self, their):
5062 if isinstance(their, self.__class__):
5064 self.spec == their.spec and
5065 self.tag == their.tag and
5066 self._expl == their._expl and
5067 self._value == their._value
5069 if hasattr(their, "__iter__"):
5070 return self._value == list(their)
5082 return self.__class__(
5086 (self._bound_min, self._bound_max)
5087 if bounds is None else bounds
5089 impl=self.tag if impl is None else impl,
5090 expl=self._expl if expl is None else expl,
5091 default=self.default if default is None else default,
5092 optional=self.optional if optional is None else optional,
5095 def __contains__(self, key):
5096 return key in self._value
5098 def append(self, value):
5099 if not isinstance(value, self.spec.__class__):
5100 raise InvalidValueType((self.spec.__class__,))
5101 if len(self._value) + 1 > self._bound_max:
5104 len(self._value) + 1,
5107 self._value.append(value)
5110 self._assert_ready()
5111 return iter(self._value)
5114 self._assert_ready()
5115 return len(self._value)
5117 def __setitem__(self, key, value):
5118 if not isinstance(value, self.spec.__class__):
5119 raise InvalidValueType((self.spec.__class__,))
5120 self._value[key] = self.spec(value=value)
5122 def __getitem__(self, key):
5123 return self._value[key]
5125 def _encoded_values(self):
5126 return [v.encode() for v in self._value]
5129 v = b"".join(self._encoded_values())
5130 return b"".join((self.tag, len_encode(len(v)), v))
5132 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5134 t, tlen, lv = tag_strip(tlv)
5135 except DecodeError as err:
5136 raise err.__class__(
5138 klass=self.__class__,
5139 decode_path=decode_path,
5144 klass=self.__class__,
5145 decode_path=decode_path,
5151 ctx_bered = ctx.get("bered", False)
5153 l, llen, v = len_decode(lv)
5154 except LenIndefForm as err:
5156 raise err.__class__(
5158 klass=self.__class__,
5159 decode_path=decode_path,
5162 l, llen, v = 0, 1, lv[1:]
5164 except DecodeError as err:
5165 raise err.__class__(
5167 klass=self.__class__,
5168 decode_path=decode_path,
5172 raise NotEnoughData(
5173 "encoded length is longer than data",
5174 klass=self.__class__,
5175 decode_path=decode_path,
5179 v, tail = v[:l], v[l:]
5181 sub_offset = offset + tlen + llen
5183 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5184 value_prev = memoryview(v[:0])
5188 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5190 sub_decode_path = decode_path + (str(len(_value)),)
5191 value, v_tail = spec.decode(
5195 decode_path=sub_decode_path,
5198 value_len = value.fulllen
5200 if value_prev.tobytes() > v[:value_len].tobytes():
5201 if ctx_bered or ctx_allow_unordered_set:
5205 "unordered " + self.asn1_type_name,
5206 klass=self.__class__,
5207 decode_path=sub_decode_path,
5210 value_prev = v[:value_len]
5211 _value.append(value)
5212 sub_offset += value_len
5216 obj = self.__class__(
5219 bounds=(self._bound_min, self._bound_max),
5222 default=self.default,
5223 optional=self.optional,
5224 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5226 except BoundsError as err:
5229 klass=self.__class__,
5230 decode_path=decode_path,
5234 if v[:EOC_LEN].tobytes() != EOC:
5237 klass=self.__class__,
5238 decode_path=decode_path,
5243 obj.ber_encoded = ber_encoded
5248 pp_console_row(next(self.pps())),
5249 ", ".join(repr(v) for v in self._value),
5252 def pps(self, decode_path=()):
5254 asn1_type_name=self.asn1_type_name,
5255 obj_name=self.__class__.__name__,
5256 decode_path=decode_path,
5257 optional=self.optional,
5258 default=self == self.default,
5259 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5260 expl=None if self._expl is None else tag_decode(self._expl),
5265 expl_offset=self.expl_offset if self.expled else None,
5266 expl_tlen=self.expl_tlen if self.expled else None,
5267 expl_llen=self.expl_llen if self.expled else None,
5268 expl_vlen=self.expl_vlen if self.expled else None,
5269 expl_lenindef=self.expl_lenindef,
5270 lenindef=self.lenindef,
5271 ber_encoded=self.ber_encoded,
5274 for i, value in enumerate(self._value):
5275 yield value.pps(decode_path=decode_path + (str(i),))
5276 for pp in self.pps_lenindef(decode_path):
5280 class SetOf(SequenceOf):
5281 """``SET OF`` sequence type
5283 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
5286 tag_default = tag_encode(form=TagFormConstructed, num=17)
5287 asn1_type_name = "SET OF"
5290 raws = self._encoded_values()
5293 return b"".join((self.tag, len_encode(len(v)), v))
5295 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5296 return super(SetOf, self)._decode(
5302 ordering_check=True,
5306 def obj_by_path(pypath): # pragma: no cover
5307 """Import object specified as string Python path
5309 Modules must be separated from classes/functions with ``:``.
5311 >>> obj_by_path("foo.bar:Baz")
5312 <class 'foo.bar.Baz'>
5313 >>> obj_by_path("foo.bar:Baz.boo")
5314 <classmethod 'foo.bar.Baz.boo'>
5316 mod, objs = pypath.rsplit(":", 1)
5317 from importlib import import_module
5318 obj = import_module(mod)
5319 for obj_name in objs.split("."):
5320 obj = getattr(obj, obj_name)
5324 def generic_decoder(): # pragma: no cover
5325 # All of this below is a big hack with self references
5326 choice = PrimitiveTypes()
5327 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
5328 choice.specs["SetOf"] = SetOf(schema=choice)
5330 choice.specs["SequenceOf%d" % i] = SequenceOf(
5334 choice.specs["Any"] = Any()
5336 # Class name equals to type name, to omit it from output
5337 class SEQUENCEOF(SequenceOf):
5345 with_decode_path=False,
5346 decode_path_only=(),
5348 def _pprint_pps(pps):
5350 if hasattr(pp, "_fields"):
5352 decode_path_only != () and
5353 pp.decode_path[:len(decode_path_only)] != decode_path_only
5356 if pp.asn1_type_name == Choice.asn1_type_name:
5358 pp_kwargs = pp._asdict()
5359 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
5360 pp = _pp(**pp_kwargs)
5361 yield pp_console_row(
5366 with_colours=with_colours,
5367 with_decode_path=with_decode_path,
5368 decode_path_len_decrease=len(decode_path_only),
5370 for row in pp_console_blob(
5372 decode_path_len_decrease=len(decode_path_only),
5376 for row in _pprint_pps(pp):
5378 return "\n".join(_pprint_pps(obj.pps()))
5379 return SEQUENCEOF(), pprint_any
5382 def main(): # pragma: no cover
5384 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
5385 parser.add_argument(
5389 help="Skip that number of bytes from the beginning",
5391 parser.add_argument(
5393 help="Python path to dictionary with OIDs",
5395 parser.add_argument(
5397 help="Python path to schema definition to use",
5399 parser.add_argument(
5400 "--defines-by-path",
5401 help="Python path to decoder's defines_by_path",
5403 parser.add_argument(
5405 action="store_true",
5406 help="Disallow BER encoding",
5408 parser.add_argument(
5409 "--print-decode-path",
5410 action="store_true",
5411 help="Print decode paths",
5413 parser.add_argument(
5414 "--decode-path-only",
5415 help="Print only specified decode path",
5417 parser.add_argument(
5419 action="store_true",
5420 help="Allow explicit tag out-of-bound",
5422 parser.add_argument(
5424 type=argparse.FileType("rb"),
5425 help="Path to DER file you want to decode",
5427 args = parser.parse_args()
5428 args.DERFile.seek(args.skip)
5429 der = memoryview(args.DERFile.read())
5430 args.DERFile.close()
5431 oids = obj_by_path(args.oids) if args.oids else {}
5433 schema = obj_by_path(args.schema)
5434 from functools import partial
5435 pprinter = partial(pprint, big_blobs=True)
5437 schema, pprinter = generic_decoder()
5439 "bered": not args.nobered,
5440 "allow_expl_oob": args.allow_expl_oob,
5442 if args.defines_by_path is not None:
5443 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
5444 obj, tail = schema().decode(der, ctx=ctx)
5448 with_colours=True if environ.get("NO_COLOR") is None else False,
5449 with_decode_path=args.print_decode_path,
5451 () if args.decode_path_only is None else
5452 tuple(args.decode_path_only.split(":"))
5456 print("\nTrailing data: %s" % hexenc(tail))
5459 if __name__ == "__main__":