3 # PyDERASN -- Python ASN.1 DER codec with abstract structures
4 # Copyright (C) 2017 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 codec with abstract structures
21 This library allows you to marshal and unmarshal various structures in
22 ASN.1 DER format, like this:
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 takes
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 object of the same type, but with different implicit/explicit tags
94 You can get objects 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 it is ready
163 to be encoded. If that kind of action is performed on unready object,
164 then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
166 All objects have ``copy()`` method, returning its copy, that can be safely
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:
192 ``expled`` (to know if explicit tag is set), ``expl_offset`` (it is
193 lesser than ``offset``), ``expl_tlen``, ``expl_llen``, ``expl_vlen``
194 (that actually equals to ordinary ``tlvlen``).
196 When error occurs, then :py:exc:`pyderasn.DecodeError` is raised.
203 All objects have ``pps()`` method, that is a generator of
204 :py:class:`pyderasn.PP` namedtuple, holding various raw information
205 about the object. If ``pps`` is called on sequences, then all underlying
206 ``PP`` will be yielded.
208 You can use :py:func:`pyderasn.pp_console_row` function, converting
209 those ``PP`` to human readable string. Actually exactly it is used for
210 all object ``repr``. But it is easy to write custom formatters.
212 >>> from pyderasn import pprint
213 >>> encoded = Integer(-12345).encode()
214 >>> obj, tail = Integer().decode(encoded)
215 >>> print(pprint(obj))
216 0 [1,1, 2] INTEGER -12345
223 ASN.1 structures often have ANY and OCTET STRING fields, that are
224 DEFINED BY some previously met ObjectIdentifier. This library provides
225 ability to specify mapping between some OID and field that must be
226 decoded with specific specification.
231 :py:class:`pyderasn.ObjectIdentifier` field inside
232 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
233 necessary for decoding structrures. For example, CMS (:rfc:`5652`)
236 class ContentInfo(Sequence):
238 ("contentType", ContentType(defines=("content", {
239 id_digestedData: DigestedData(),
240 id_signedData: SignedData(),
242 ("content", Any(expl=tag_ctxc(0))),
245 ``contentType`` field tells that it defines that ``content`` must be
246 decoded with ``SignedData`` specification, if ``contentType`` equals to
247 ``id-signedData``. The same applies to ``DigestedData``. If
248 ``contentType`` contains unknown OID, then no automatic decoding is
251 Following types can be automatically decoded (DEFINED BY):
253 * :py:class:`pyderasn.Any`
254 * :py:class:`pyderasn.OctetString`
255 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
256 ``Any``/``OctetString``-s
258 When any of those fields is automatically decoded, then ``.defined``
259 attribute contains ``(OID, value)`` tuple. OID tell by which OID it was
260 defined, ``value`` contains corresponding decoded value. For example
261 above, ``content_info["content"].defined == (id_signedData,
264 defines_by_path kwarg
265 _____________________
267 Sometimes you either can not or do not want to explicitly set *defines*
268 in the scheme. You can dynamically apply those definitions when calling
269 ``.decode()`` method.
271 Decode method takes optional ``defines_by_path`` keyword argument that
272 must be sequence of following tuples::
274 (decode_path, defines)
276 where ``decode_path`` is a tuple holding so-called decode path to the
277 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
278 ``defines``, holding exactly the same value as accepted in its keyword
281 For example, again for CMS, you want to automatically decode
282 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
283 structures it may hold. Also, automatically decode ``controlSequence``
286 content_info, tail = ContentInfo().decode(data, defines_by_path=(
289 ("content", {id_signedData: SignedData()}),
294 decode_path_defby(id_signedData),
299 id_cct_PKIData: PKIData(),
300 id_cct_PKIResponse: PKIResponse(),
306 decode_path_defby(id_signedData),
309 decode_path_defby(id_cct_PKIResponse),
315 id_cmc_recipientNonce: RecipientNonce(),
316 id_cmc_senderNonce: SenderNonce(),
317 id_cmc_statusInfoV2: CMCStatusInfoV2(),
318 id_cmc_transactionId: TransactionId(),
323 Pay attention for :py:func:`pyderasn.decode_path_defby` and ``any``.
324 First function is useful for path construction when some automatic
325 decoding is already done. ``any`` is used for human readability and
326 means literally any value it meet -- useful for sequence and set of-s.
333 .. autoclass:: pyderasn.Boolean
338 .. autoclass:: pyderasn.Integer
343 .. autoclass:: pyderasn.BitString
348 .. autoclass:: pyderasn.OctetString
353 .. autoclass:: pyderasn.Null
358 .. autoclass:: pyderasn.ObjectIdentifier
363 .. autoclass:: pyderasn.Enumerated
367 .. autoclass:: pyderasn.CommonString
371 .. autoclass:: pyderasn.UTCTime
372 :members: __init__, todatetime
376 .. autoclass:: pyderasn.GeneralizedTime
383 .. autoclass:: pyderasn.Choice
388 .. autoclass:: PrimitiveTypes
392 .. autoclass:: pyderasn.Any
400 .. autoclass:: pyderasn.Sequence
405 .. autoclass:: pyderasn.Set
410 .. autoclass:: pyderasn.SequenceOf
415 .. autoclass:: pyderasn.SetOf
421 .. autofunction:: pyderasn.hexenc
422 .. autofunction:: pyderasn.hexdec
423 .. autofunction:: pyderasn.tag_encode
424 .. autofunction:: pyderasn.tag_decode
425 .. autofunction:: pyderasn.tag_ctxp
426 .. autofunction:: pyderasn.tag_ctxc
427 .. autoclass:: pyderasn.Obj
430 from codecs import getdecoder
431 from codecs import getencoder
432 from collections import namedtuple
433 from collections import OrderedDict
434 from datetime import datetime
435 from math import ceil
437 from six import add_metaclass
438 from six import binary_type
439 from six import byte2int
440 from six import indexbytes
441 from six import int2byte
442 from six import integer_types
443 from six import iterbytes
445 from six import string_types
446 from six import text_type
447 from six.moves import xrange as six_xrange
489 "TagClassApplication",
493 "TagFormConstructed",
504 TagClassUniversal = 0
505 TagClassApplication = 1 << 6
506 TagClassContext = 1 << 7
507 TagClassPrivate = 1 << 6 | 1 << 7
509 TagFormConstructed = 1 << 5
512 TagClassApplication: "APPLICATION ",
513 TagClassPrivate: "PRIVATE ",
514 TagClassUniversal: "UNIV ",
518 ########################################################################
520 ########################################################################
522 class DecodeError(Exception):
523 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
525 :param str msg: reason of decode failing
526 :param klass: optional exact DecodeError inherited class (like
527 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
528 :py:exc:`InvalidLength`)
529 :param decode_path: tuple of strings. It contains human
530 readable names of the fields through which
531 decoding process has passed
532 :param int offset: binary offset where failure happened
534 super(DecodeError, self).__init__()
537 self.decode_path = decode_path
543 "" if self.klass is None else self.klass.__name__,
545 ("(%s)" % ".".join(self.decode_path))
546 if len(self.decode_path) > 0 else ""
548 ("(at %d)" % self.offset) if self.offset > 0 else "",
554 return "%s(%s)" % (self.__class__.__name__, self)
557 class NotEnoughData(DecodeError):
561 class TagMismatch(DecodeError):
565 class InvalidLength(DecodeError):
569 class InvalidOID(DecodeError):
573 class ObjUnknown(ValueError):
574 def __init__(self, name):
575 super(ObjUnknown, self).__init__()
579 return "object is unknown: %s" % self.name
582 return "%s(%s)" % (self.__class__.__name__, self)
585 class ObjNotReady(ValueError):
586 def __init__(self, name):
587 super(ObjNotReady, self).__init__()
591 return "object is not ready: %s" % self.name
594 return "%s(%s)" % (self.__class__.__name__, self)
597 class InvalidValueType(ValueError):
598 def __init__(self, expected_types):
599 super(InvalidValueType, self).__init__()
600 self.expected_types = expected_types
603 return "invalid value type, expected: %s" % ", ".join(
604 [repr(t) for t in self.expected_types]
608 return "%s(%s)" % (self.__class__.__name__, self)
611 class BoundsError(ValueError):
612 def __init__(self, bound_min, value, bound_max):
613 super(BoundsError, self).__init__()
614 self.bound_min = bound_min
616 self.bound_max = bound_max
619 return "unsatisfied bounds: %s <= %s <= %s" % (
626 return "%s(%s)" % (self.__class__.__name__, self)
629 ########################################################################
631 ########################################################################
633 _hexdecoder = getdecoder("hex")
634 _hexencoder = getencoder("hex")
638 """Binary data to hexadecimal string convert
640 return _hexdecoder(data)[0]
644 """Hexadecimal string to binary data convert
646 return _hexencoder(data)[0].decode("ascii")
649 def int_bytes_len(num, byte_len=8):
652 return int(ceil(float(num.bit_length()) / byte_len))
655 def zero_ended_encode(num):
656 octets = bytearray(int_bytes_len(num, 7))
658 octets[i] = num & 0x7F
662 octets[i] = 0x80 | (num & 0x7F)
668 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
669 """Encode tag to binary form
671 :param int num: tag's number
672 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
673 :py:data:`pyderasn.TagClassContext`,
674 :py:data:`pyderasn.TagClassApplication`,
675 :py:data:`pyderasn.TagClassPrivate`)
676 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
677 :py:data:`pyderasn.TagFormConstructed`)
681 return int2byte(klass | form | num)
682 # [XX|X|11111][1.......][1.......] ... [0.......]
683 return int2byte(klass | form | 31) + zero_ended_encode(num)
687 """Decode tag from binary form
691 No validation is performed, assuming that it has already passed.
693 It returns tuple with three integers, as
694 :py:func:`pyderasn.tag_encode` accepts.
696 first_octet = byte2int(tag)
697 klass = first_octet & 0xC0
698 form = first_octet & 0x20
699 if first_octet & 0x1F < 0x1F:
700 return (klass, form, first_octet & 0x1F)
702 for octet in iterbytes(tag[1:]):
705 return (klass, form, num)
709 """Create CONTEXT PRIMITIVE tag
711 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
715 """Create CONTEXT CONSTRUCTED tag
717 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
721 """Take off tag from the data
723 :returns: (encoded tag, tag length, remaining data)
726 raise NotEnoughData("no data at all")
727 if byte2int(data) & 0x1F < 31:
728 return data[:1], 1, data[1:]
733 raise DecodeError("unfinished tag")
734 if indexbytes(data, i) & 0x80 == 0:
737 return data[:i], i, data[i:]
743 octets = bytearray(int_bytes_len(l) + 1)
744 octets[0] = 0x80 | (len(octets) - 1)
745 for i in six_xrange(len(octets) - 1, 0, -1):
751 def len_decode(data):
753 raise NotEnoughData("no data at all")
754 first_octet = byte2int(data)
755 if first_octet & 0x80 == 0:
756 return first_octet, 1, data[1:]
757 octets_num = first_octet & 0x7F
758 if octets_num + 1 > len(data):
759 raise NotEnoughData("encoded length is longer than data")
761 raise DecodeError("long form instead of short one")
762 if byte2int(data[1:]) == 0:
763 raise DecodeError("leading zeros")
765 for v in iterbytes(data[1:1 + octets_num]):
768 raise DecodeError("long form instead of short one")
769 return l, 1 + octets_num, data[1 + octets_num:]
772 ########################################################################
774 ########################################################################
776 class AutoAddSlots(type):
777 def __new__(cls, name, bases, _dict):
778 _dict["__slots__"] = _dict.get("__slots__", ())
779 return type.__new__(cls, name, bases, _dict)
782 @add_metaclass(AutoAddSlots)
784 """Common ASN.1 object class
786 All ASN.1 types are inherited from it. It has metaclass that
787 automatically adds ``__slots__`` to all inherited classes.
808 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
809 self._expl = getattr(self, "expl", None) if expl is None else expl
810 if self.tag != self.tag_default and self._expl is not None:
812 "implicit and explicit tags can not be set simultaneously"
814 if default is not None:
816 self.optional = optional
817 self.offset, self.llen, self.vlen = _decoded
821 def ready(self): # pragma: no cover
822 """Is object ready to be encoded?
824 raise NotImplementedError()
826 def _assert_ready(self):
828 raise ObjNotReady(self.__class__.__name__)
832 """Is object decoded?
834 return (self.llen + self.vlen) > 0
836 def copy(self): # pragma: no cover
837 """Make a copy of object, safe to be mutated
839 raise NotImplementedError()
847 return self.tlen + self.llen + self.vlen
849 def __str__(self): # pragma: no cover
850 return self.__bytes__() if PY2 else self.__unicode__()
852 def __ne__(self, their):
853 return not(self == their)
855 def __gt__(self, their): # pragma: no cover
856 return not(self < their)
858 def __le__(self, their): # pragma: no cover
859 return (self == their) or (self < their)
861 def __ge__(self, their): # pragma: no cover
862 return (self == their) or (self > their)
864 def _encode(self): # pragma: no cover
865 raise NotImplementedError()
867 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None): # pragma: no cover
868 raise NotImplementedError()
872 if self._expl is None:
874 return b"".join((self._expl, len_encode(len(raw)), raw))
876 def decode(self, data, offset=0, leavemm=False, decode_path=(), defines_by_path=None):
879 :param data: either binary or memoryview
880 :param int offset: initial data's offset
881 :param bool leavemm: do we need to leave memoryview of remaining
882 data as is, or convert it to bytes otherwise
883 :param defines_by_path: :ref:`Read about DEFINED BY <definedby>`
884 :returns: (Obj, remaining data)
886 tlv = memoryview(data)
887 if self._expl is None:
888 obj, tail = self._decode(
891 decode_path=decode_path,
892 defines_by_path=defines_by_path,
896 t, tlen, lv = tag_strip(tlv)
897 except DecodeError as err:
900 klass=self.__class__,
901 decode_path=decode_path,
906 klass=self.__class__,
907 decode_path=decode_path,
911 l, llen, v = len_decode(lv)
912 except DecodeError as err:
915 klass=self.__class__,
916 decode_path=decode_path,
921 "encoded length is longer than data",
922 klass=self.__class__,
923 decode_path=decode_path,
926 obj, tail = self._decode(
928 offset=offset + tlen + llen,
929 decode_path=decode_path,
930 defines_by_path=defines_by_path,
932 return obj, (tail if leavemm else tail.tobytes())
936 return self._expl is not None
944 return len(self._expl)
948 return len(len_encode(self.tlvlen))
951 def expl_offset(self):
952 return self.offset - self.expl_tlen - self.expl_llen
959 def expl_tlvlen(self):
960 return self.expl_tlen + self.expl_llen + self.expl_vlen
963 def decode_path_defby(defined_by):
964 """DEFINED BY representation inside decode path
966 return "DEFINED BY (%s)" % defined_by
969 ########################################################################
971 ########################################################################
973 PP = namedtuple("PP", (
995 asn1_type_name="unknown",
1034 def pp_console_row(pp, oids=None, with_offsets=False, with_blob=True):
1037 cols.append("%5d%s [%d,%d,%4d]" % (
1040 " " if pp.expl_offset is None else
1041 ("-%d" % (pp.offset - pp.expl_offset))
1047 if len(pp.decode_path) > 0:
1048 cols.append(" ." * (len(pp.decode_path)))
1049 cols.append("%s:" % pp.decode_path[-1])
1050 if pp.expl is not None:
1051 klass, _, num = pp.expl
1052 cols.append("[%s%d] EXPLICIT" % (TagClassReprs[klass], num))
1053 if pp.impl is not None:
1054 klass, _, num = pp.impl
1055 cols.append("[%s%d]" % (TagClassReprs[klass], num))
1056 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1057 cols.append(pp.obj_name)
1058 cols.append(pp.asn1_type_name)
1059 if pp.value is not None:
1062 oids is not None and
1063 pp.asn1_type_name == ObjectIdentifier.asn1_type_name and
1066 value = "%s (%s)" % (oids[value], pp.value)
1069 if isinstance(pp.blob, binary_type):
1070 cols.append(hexenc(pp.blob))
1071 elif isinstance(pp.blob, tuple):
1072 cols.append(", ".join(pp.blob))
1074 cols.append("OPTIONAL")
1076 cols.append("DEFAULT")
1077 return " ".join(cols)
1080 def pp_console_blob(pp):
1081 cols = [" " * len("XXXXXYY [X,X,XXXX]")]
1082 if len(pp.decode_path) > 0:
1083 cols.append(" ." * (len(pp.decode_path) + 1))
1084 if isinstance(pp.blob, binary_type):
1085 blob = hexenc(pp.blob).upper()
1086 for i in range(0, len(blob), 32):
1087 chunk = blob[i:i + 32]
1088 yield " ".join(cols + [":".join(
1089 chunk[j:j + 2] for j in range(0, len(chunk), 2)
1091 elif isinstance(pp.blob, tuple):
1092 yield " ".join(cols + [", ".join(pp.blob)])
1095 def pprint(obj, oids=None, big_blobs=False):
1096 """Pretty print object
1098 :param Obj obj: object you want to pretty print
1099 :param oids: ``OID <-> humand readable string`` dictionary. When OID
1100 from it is met, then its humand readable form is printed
1101 :param big_blobs: if large binary objects are met (like OctetString
1102 values), do we need to print them too, on separate
1105 def _pprint_pps(pps):
1107 if hasattr(pp, "_fields"):
1109 yield pp_console_row(
1115 for row in pp_console_blob(pp):
1118 yield pp_console_row(pp, oids=oids, with_offsets=True)
1120 for row in _pprint_pps(pp):
1122 return "\n".join(_pprint_pps(obj.pps()))
1125 ########################################################################
1126 # ASN.1 primitive types
1127 ########################################################################
1130 """``BOOLEAN`` boolean type
1132 >>> b = Boolean(True)
1134 >>> b == Boolean(True)
1140 tag_default = tag_encode(1)
1141 asn1_type_name = "BOOLEAN"
1153 :param value: set the value. Either boolean type, or
1154 :py:class:`pyderasn.Boolean` object
1155 :param bytes impl: override default tag with ``IMPLICIT`` one
1156 :param bytes expl: override default tag with ``EXPLICIT`` one
1157 :param default: set default value. Type same as in ``value``
1158 :param bool optional: is object ``OPTIONAL`` in sequence
1160 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1161 self._value = None if value is None else self._value_sanitize(value)
1162 if default is not None:
1163 default = self._value_sanitize(default)
1164 self.default = self.__class__(
1170 self._value = default
1172 def _value_sanitize(self, value):
1173 if issubclass(value.__class__, Boolean):
1175 if isinstance(value, bool):
1177 raise InvalidValueType((self.__class__, bool))
1181 return self._value is not None
1184 obj = self.__class__()
1185 obj._value = self._value
1187 obj._expl = self._expl
1188 obj.default = self.default
1189 obj.optional = self.optional
1190 obj.offset = self.offset
1191 obj.llen = self.llen
1192 obj.vlen = self.vlen
1195 def __nonzero__(self):
1196 self._assert_ready()
1200 self._assert_ready()
1203 def __eq__(self, their):
1204 if isinstance(their, bool):
1205 return self._value == their
1206 if not issubclass(their.__class__, Boolean):
1209 self._value == their._value and
1210 self.tag == their.tag and
1211 self._expl == their._expl
1222 return self.__class__(
1224 impl=self.tag if impl is None else impl,
1225 expl=self._expl if expl is None else expl,
1226 default=self.default if default is None else default,
1227 optional=self.optional if optional is None else optional,
1231 self._assert_ready()
1235 (b"\xFF" if self._value else b"\x00"),
1238 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
1240 t, _, lv = tag_strip(tlv)
1241 except DecodeError as err:
1242 raise err.__class__(
1244 klass=self.__class__,
1245 decode_path=decode_path,
1250 klass=self.__class__,
1251 decode_path=decode_path,
1255 l, _, v = len_decode(lv)
1256 except DecodeError as err:
1257 raise err.__class__(
1259 klass=self.__class__,
1260 decode_path=decode_path,
1264 raise InvalidLength(
1265 "Boolean's length must be equal to 1",
1266 klass=self.__class__,
1267 decode_path=decode_path,
1271 raise NotEnoughData(
1272 "encoded length is longer than data",
1273 klass=self.__class__,
1274 decode_path=decode_path,
1277 first_octet = byte2int(v)
1278 if first_octet == 0:
1280 elif first_octet == 0xFF:
1284 "unacceptable Boolean value",
1285 klass=self.__class__,
1286 decode_path=decode_path,
1289 obj = self.__class__(
1293 default=self.default,
1294 optional=self.optional,
1295 _decoded=(offset, 1, 1),
1300 return pp_console_row(next(self.pps()))
1302 def pps(self, decode_path=()):
1304 asn1_type_name=self.asn1_type_name,
1305 obj_name=self.__class__.__name__,
1306 decode_path=decode_path,
1307 value=str(self._value) if self.ready else None,
1308 optional=self.optional,
1309 default=self == self.default,
1310 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1311 expl=None if self._expl is None else tag_decode(self._expl),
1316 expl_offset=self.expl_offset if self.expled else None,
1317 expl_tlen=self.expl_tlen if self.expled else None,
1318 expl_llen=self.expl_llen if self.expled else None,
1319 expl_vlen=self.expl_vlen if self.expled else None,
1324 """``INTEGER`` integer type
1326 >>> b = Integer(-123)
1328 >>> b == Integer(-123)
1333 >>> Integer(2, bounds=(1, 3))
1335 >>> Integer(5, bounds=(1, 3))
1336 Traceback (most recent call last):
1337 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1341 class Version(Integer):
1348 >>> v = Version("v1")
1355 {'v3': 2, 'v1': 0, 'v2': 1}
1357 __slots__ = ("specs", "_bound_min", "_bound_max")
1358 tag_default = tag_encode(2)
1359 asn1_type_name = "INTEGER"
1373 :param value: set the value. Either integer type, named value
1374 (if ``schema`` is specified in the class), or
1375 :py:class:`pyderasn.Integer` object
1376 :param bounds: set ``(MIN, MAX)`` value constraint.
1377 (-inf, +inf) by default
1378 :param bytes impl: override default tag with ``IMPLICIT`` one
1379 :param bytes expl: override default tag with ``EXPLICIT`` one
1380 :param default: set default value. Type same as in ``value``
1381 :param bool optional: is object ``OPTIONAL`` in sequence
1383 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
1385 specs = getattr(self, "schema", {}) if _specs is None else _specs
1386 self.specs = specs if isinstance(specs, dict) else dict(specs)
1387 self._bound_min, self._bound_max = getattr(
1390 (float("-inf"), float("+inf")),
1391 ) if bounds is None else bounds
1392 if value is not None:
1393 self._value = self._value_sanitize(value)
1394 if default is not None:
1395 default = self._value_sanitize(default)
1396 self.default = self.__class__(
1402 if self._value is None:
1403 self._value = default
1405 def _value_sanitize(self, value):
1406 if issubclass(value.__class__, Integer):
1407 value = value._value
1408 elif isinstance(value, integer_types):
1410 elif isinstance(value, str):
1411 value = self.specs.get(value)
1413 raise ObjUnknown("integer value: %s" % value)
1415 raise InvalidValueType((self.__class__, int, str))
1416 if not self._bound_min <= value <= self._bound_max:
1417 raise BoundsError(self._bound_min, value, self._bound_max)
1422 return self._value is not None
1425 obj = self.__class__(_specs=self.specs)
1426 obj._value = self._value
1427 obj._bound_min = self._bound_min
1428 obj._bound_max = self._bound_max
1430 obj._expl = self._expl
1431 obj.default = self.default
1432 obj.optional = self.optional
1433 obj.offset = self.offset
1434 obj.llen = self.llen
1435 obj.vlen = self.vlen
1439 self._assert_ready()
1440 return int(self._value)
1443 self._assert_ready()
1446 bytes(self._expl or b"") +
1447 str(self._value).encode("ascii"),
1450 def __eq__(self, their):
1451 if isinstance(their, integer_types):
1452 return self._value == their
1453 if not issubclass(their.__class__, Integer):
1456 self._value == their._value and
1457 self.tag == their.tag and
1458 self._expl == their._expl
1461 def __lt__(self, their):
1462 return self._value < their._value
1466 for name, value in self.specs.items():
1467 if value == self._value:
1479 return self.__class__(
1482 (self._bound_min, self._bound_max)
1483 if bounds is None else bounds
1485 impl=self.tag if impl is None else impl,
1486 expl=self._expl if expl is None else expl,
1487 default=self.default if default is None else default,
1488 optional=self.optional if optional is None else optional,
1493 self._assert_ready()
1497 octets = bytearray([0])
1501 octets = bytearray()
1503 octets.append((value & 0xFF) ^ 0xFF)
1505 if len(octets) == 0 or octets[-1] & 0x80 == 0:
1508 octets = bytearray()
1510 octets.append(value & 0xFF)
1512 if octets[-1] & 0x80 > 0:
1515 octets = bytes(octets)
1517 bytes_len = ceil(value.bit_length() / 8) or 1
1520 octets = value.to_bytes(
1525 except OverflowError:
1529 return b"".join((self.tag, len_encode(len(octets)), octets))
1531 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
1533 t, _, lv = tag_strip(tlv)
1534 except DecodeError as err:
1535 raise err.__class__(
1537 klass=self.__class__,
1538 decode_path=decode_path,
1543 klass=self.__class__,
1544 decode_path=decode_path,
1548 l, llen, v = len_decode(lv)
1549 except DecodeError as err:
1550 raise err.__class__(
1552 klass=self.__class__,
1553 decode_path=decode_path,
1557 raise NotEnoughData(
1558 "encoded length is longer than data",
1559 klass=self.__class__,
1560 decode_path=decode_path,
1564 raise NotEnoughData(
1566 klass=self.__class__,
1567 decode_path=decode_path,
1570 v, tail = v[:l], v[l:]
1571 first_octet = byte2int(v)
1573 second_octet = byte2int(v[1:])
1575 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
1576 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
1579 "non normalized integer",
1580 klass=self.__class__,
1581 decode_path=decode_path,
1586 if first_octet & 0x80 > 0:
1587 octets = bytearray()
1588 for octet in bytearray(v):
1589 octets.append(octet ^ 0xFF)
1590 for octet in octets:
1591 value = (value << 8) | octet
1595 for octet in bytearray(v):
1596 value = (value << 8) | octet
1598 value = int.from_bytes(v, byteorder="big", signed=True)
1600 obj = self.__class__(
1602 bounds=(self._bound_min, self._bound_max),
1605 default=self.default,
1606 optional=self.optional,
1608 _decoded=(offset, llen, l),
1610 except BoundsError as err:
1613 klass=self.__class__,
1614 decode_path=decode_path,
1620 return pp_console_row(next(self.pps()))
1622 def pps(self, decode_path=()):
1624 asn1_type_name=self.asn1_type_name,
1625 obj_name=self.__class__.__name__,
1626 decode_path=decode_path,
1627 value=(self.named or str(self._value)) if self.ready else None,
1628 optional=self.optional,
1629 default=self == self.default,
1630 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1631 expl=None if self._expl is None else tag_decode(self._expl),
1636 expl_offset=self.expl_offset if self.expled else None,
1637 expl_tlen=self.expl_tlen if self.expled else None,
1638 expl_llen=self.expl_llen if self.expled else None,
1639 expl_vlen=self.expl_vlen if self.expled else None,
1643 class BitString(Obj):
1644 """``BIT STRING`` bit string type
1646 >>> BitString(b"hello world")
1647 BIT STRING 88 bits 68656c6c6f20776f726c64
1650 >>> b == b"hello world"
1655 >>> b = BitString("'010110000000'B")
1656 BIT STRING 12 bits 5800
1659 >>> b[0], b[1], b[2], b[3]
1660 (False, True, False, True)
1664 [False, True, False, True, True, False, False, False, False, False, False, False]
1668 class KeyUsage(BitString):
1670 ('digitalSignature', 0),
1671 ('nonRepudiation', 1),
1672 ('keyEncipherment', 2),
1675 >>> b = KeyUsage(('keyEncipherment', 'nonRepudiation'))
1676 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
1678 ['nonRepudiation', 'keyEncipherment']
1680 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
1682 __slots__ = ("specs",)
1683 tag_default = tag_encode(3)
1684 asn1_type_name = "BIT STRING"
1697 :param value: set the value. Either binary type, tuple of named
1698 values (if ``schema`` is specified in the class),
1699 string in ``'XXX...'B`` form, or
1700 :py:class:`pyderasn.BitString` object
1701 :param bytes impl: override default tag with ``IMPLICIT`` one
1702 :param bytes expl: override default tag with ``EXPLICIT`` one
1703 :param default: set default value. Type same as in ``value``
1704 :param bool optional: is object ``OPTIONAL`` in sequence
1706 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
1707 specs = getattr(self, "schema", {}) if _specs is None else _specs
1708 self.specs = specs if isinstance(specs, dict) else dict(specs)
1709 self._value = None if value is None else self._value_sanitize(value)
1710 if default is not None:
1711 default = self._value_sanitize(default)
1712 self.default = self.__class__(
1718 self._value = default
1720 def _bits2octets(self, bits):
1721 if len(self.specs) > 0:
1722 bits = bits.rstrip("0")
1724 bits += "0" * ((8 - (bit_len % 8)) % 8)
1725 octets = bytearray(len(bits) // 8)
1726 for i in six_xrange(len(octets)):
1727 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
1728 return bit_len, bytes(octets)
1730 def _value_sanitize(self, value):
1731 if issubclass(value.__class__, BitString):
1733 if isinstance(value, (string_types, binary_type)):
1735 isinstance(value, string_types) and
1736 value.startswith("'") and
1737 value.endswith("'B")
1740 if not set(value) <= set(("0", "1")):
1741 raise ValueError("B's coding contains unacceptable chars")
1742 return self._bits2octets(value)
1743 elif isinstance(value, binary_type):
1744 return (len(value) * 8, value)
1746 raise InvalidValueType((
1751 if isinstance(value, tuple):
1754 isinstance(value[0], integer_types) and
1755 isinstance(value[1], binary_type)
1760 bit = self.specs.get(name)
1762 raise ObjUnknown("BitString value: %s" % name)
1765 return self._bits2octets("")
1767 return self._bits2octets("".join(
1768 ("1" if bit in bits else "0")
1769 for bit in six_xrange(max(bits) + 1)
1771 raise InvalidValueType((self.__class__, binary_type, string_types))
1775 return self._value is not None
1778 obj = self.__class__(_specs=self.specs)
1780 if value is not None:
1781 value = (value[0], value[1])
1784 obj._expl = self._expl
1785 obj.default = self.default
1786 obj.optional = self.optional
1787 obj.offset = self.offset
1788 obj.llen = self.llen
1789 obj.vlen = self.vlen
1793 self._assert_ready()
1794 for i in six_xrange(self._value[0]):
1799 self._assert_ready()
1800 return self._value[0]
1802 def __bytes__(self):
1803 self._assert_ready()
1804 return self._value[1]
1806 def __eq__(self, their):
1807 if isinstance(their, bytes):
1808 return self._value[1] == their
1809 if not issubclass(their.__class__, BitString):
1812 self._value == their._value and
1813 self.tag == their.tag and
1814 self._expl == their._expl
1819 return [name for name, bit in self.specs.items() if self[bit]]
1829 return self.__class__(
1831 impl=self.tag if impl is None else impl,
1832 expl=self._expl if expl is None else expl,
1833 default=self.default if default is None else default,
1834 optional=self.optional if optional is None else optional,
1838 def __getitem__(self, key):
1839 if isinstance(key, int):
1840 bit_len, octets = self._value
1844 byte2int(memoryview(octets)[key // 8:]) >>
1847 if isinstance(key, string_types):
1848 value = self.specs.get(key)
1850 raise ObjUnknown("BitString value: %s" % key)
1852 raise InvalidValueType((int, str))
1855 self._assert_ready()
1856 bit_len, octets = self._value
1859 len_encode(len(octets) + 1),
1860 int2byte((8 - bit_len % 8) % 8),
1864 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
1866 t, _, lv = tag_strip(tlv)
1867 except DecodeError as err:
1868 raise err.__class__(
1870 klass=self.__class__,
1871 decode_path=decode_path,
1876 klass=self.__class__,
1877 decode_path=decode_path,
1881 l, llen, v = len_decode(lv)
1882 except DecodeError as err:
1883 raise err.__class__(
1885 klass=self.__class__,
1886 decode_path=decode_path,
1890 raise NotEnoughData(
1891 "encoded length is longer than data",
1892 klass=self.__class__,
1893 decode_path=decode_path,
1897 raise NotEnoughData(
1899 klass=self.__class__,
1900 decode_path=decode_path,
1903 pad_size = byte2int(v)
1904 if l == 1 and pad_size != 0:
1906 "invalid empty value",
1907 klass=self.__class__,
1908 decode_path=decode_path,
1914 klass=self.__class__,
1915 decode_path=decode_path,
1918 if byte2int(v[-1:]) & ((1 << pad_size) - 1) != 0:
1921 klass=self.__class__,
1922 decode_path=decode_path,
1925 v, tail = v[:l], v[l:]
1926 obj = self.__class__(
1927 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
1930 default=self.default,
1931 optional=self.optional,
1933 _decoded=(offset, llen, l),
1938 return pp_console_row(next(self.pps()))
1940 def pps(self, decode_path=()):
1944 bit_len, blob = self._value
1945 value = "%d bits" % bit_len
1946 if len(self.specs) > 0:
1947 blob = tuple(self.named)
1949 asn1_type_name=self.asn1_type_name,
1950 obj_name=self.__class__.__name__,
1951 decode_path=decode_path,
1954 optional=self.optional,
1955 default=self == self.default,
1956 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1957 expl=None if self._expl is None else tag_decode(self._expl),
1962 expl_offset=self.expl_offset if self.expled else None,
1963 expl_tlen=self.expl_tlen if self.expled else None,
1964 expl_llen=self.expl_llen if self.expled else None,
1965 expl_vlen=self.expl_vlen if self.expled else None,
1969 class OctetString(Obj):
1970 """``OCTET STRING`` binary string type
1972 >>> s = OctetString(b"hello world")
1973 OCTET STRING 11 bytes 68656c6c6f20776f726c64
1974 >>> s == OctetString(b"hello world")
1979 >>> OctetString(b"hello", bounds=(4, 4))
1980 Traceback (most recent call last):
1981 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
1982 >>> OctetString(b"hell", bounds=(4, 4))
1983 OCTET STRING 4 bytes 68656c6c
1985 __slots__ = ("_bound_min", "_bound_max", "defined")
1986 tag_default = tag_encode(4)
1987 asn1_type_name = "OCTET STRING"
2000 :param value: set the value. Either binary type, or
2001 :py:class:`pyderasn.OctetString` object
2002 :param bounds: set ``(MIN, MAX)`` value size constraint.
2003 (-inf, +inf) by default
2004 :param bytes impl: override default tag with ``IMPLICIT`` one
2005 :param bytes expl: override default tag with ``EXPLICIT`` one
2006 :param default: set default value. Type same as in ``value``
2007 :param bool optional: is object ``OPTIONAL`` in sequence
2009 super(OctetString, self).__init__(
2017 self._bound_min, self._bound_max = getattr(
2021 ) if bounds is None else bounds
2022 if value is not None:
2023 self._value = self._value_sanitize(value)
2024 if default is not None:
2025 default = self._value_sanitize(default)
2026 self.default = self.__class__(
2031 if self._value is None:
2032 self._value = default
2035 def _value_sanitize(self, value):
2036 if issubclass(value.__class__, OctetString):
2037 value = value._value
2038 elif isinstance(value, binary_type):
2041 raise InvalidValueType((self.__class__, bytes))
2042 if not self._bound_min <= len(value) <= self._bound_max:
2043 raise BoundsError(self._bound_min, len(value), self._bound_max)
2048 return self._value is not None
2051 obj = self.__class__()
2052 obj._value = self._value
2053 obj._bound_min = self._bound_min
2054 obj._bound_max = self._bound_max
2056 obj._expl = self._expl
2057 obj.default = self.default
2058 obj.optional = self.optional
2059 obj.offset = self.offset
2060 obj.llen = self.llen
2061 obj.vlen = self.vlen
2064 def __bytes__(self):
2065 self._assert_ready()
2068 def __eq__(self, their):
2069 if isinstance(their, binary_type):
2070 return self._value == their
2071 if not issubclass(their.__class__, OctetString):
2074 self._value == their._value and
2075 self.tag == their.tag and
2076 self._expl == their._expl
2079 def __lt__(self, their):
2080 return self._value < their._value
2091 return self.__class__(
2094 (self._bound_min, self._bound_max)
2095 if bounds is None else bounds
2097 impl=self.tag if impl is None else impl,
2098 expl=self._expl if expl is None else expl,
2099 default=self.default if default is None else default,
2100 optional=self.optional if optional is None else optional,
2104 self._assert_ready()
2107 len_encode(len(self._value)),
2111 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
2113 t, _, lv = tag_strip(tlv)
2114 except DecodeError as err:
2115 raise err.__class__(
2117 klass=self.__class__,
2118 decode_path=decode_path,
2123 klass=self.__class__,
2124 decode_path=decode_path,
2128 l, llen, v = len_decode(lv)
2129 except DecodeError as err:
2130 raise err.__class__(
2132 klass=self.__class__,
2133 decode_path=decode_path,
2137 raise NotEnoughData(
2138 "encoded length is longer than data",
2139 klass=self.__class__,
2140 decode_path=decode_path,
2143 v, tail = v[:l], v[l:]
2145 obj = self.__class__(
2147 bounds=(self._bound_min, self._bound_max),
2150 default=self.default,
2151 optional=self.optional,
2152 _decoded=(offset, llen, l),
2154 except BoundsError as err:
2157 klass=self.__class__,
2158 decode_path=decode_path,
2164 return pp_console_row(next(self.pps()))
2166 def pps(self, decode_path=()):
2168 asn1_type_name=self.asn1_type_name,
2169 obj_name=self.__class__.__name__,
2170 decode_path=decode_path,
2171 value=("%d bytes" % len(self._value)) if self.ready else None,
2172 blob=self._value if self.ready else None,
2173 optional=self.optional,
2174 default=self == self.default,
2175 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2176 expl=None if self._expl is None else tag_decode(self._expl),
2181 expl_offset=self.expl_offset if self.expled else None,
2182 expl_tlen=self.expl_tlen if self.expled else None,
2183 expl_llen=self.expl_llen if self.expled else None,
2184 expl_vlen=self.expl_vlen if self.expled else None,
2186 defined_by, defined = self.defined or (None, None)
2187 if defined_by is not None:
2189 decode_path=decode_path + (decode_path_defby(defined_by),)
2194 """``NULL`` null object
2202 tag_default = tag_encode(5)
2203 asn1_type_name = "NULL"
2207 value=None, # unused, but Sequence passes it
2214 :param bytes impl: override default tag with ``IMPLICIT`` one
2215 :param bytes expl: override default tag with ``EXPLICIT`` one
2216 :param bool optional: is object ``OPTIONAL`` in sequence
2218 super(Null, self).__init__(impl, expl, None, optional, _decoded)
2226 obj = self.__class__()
2228 obj._expl = self._expl
2229 obj.default = self.default
2230 obj.optional = self.optional
2231 obj.offset = self.offset
2232 obj.llen = self.llen
2233 obj.vlen = self.vlen
2236 def __eq__(self, their):
2237 if not issubclass(their.__class__, Null):
2240 self.tag == their.tag and
2241 self._expl == their._expl
2251 return self.__class__(
2252 impl=self.tag if impl is None else impl,
2253 expl=self._expl if expl is None else expl,
2254 optional=self.optional if optional is None else optional,
2258 return self.tag + len_encode(0)
2260 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
2262 t, _, lv = tag_strip(tlv)
2263 except DecodeError as err:
2264 raise err.__class__(
2266 klass=self.__class__,
2267 decode_path=decode_path,
2272 klass=self.__class__,
2273 decode_path=decode_path,
2277 l, _, v = len_decode(lv)
2278 except DecodeError as err:
2279 raise err.__class__(
2281 klass=self.__class__,
2282 decode_path=decode_path,
2286 raise InvalidLength(
2287 "Null must have zero length",
2288 klass=self.__class__,
2289 decode_path=decode_path,
2292 obj = self.__class__(
2295 optional=self.optional,
2296 _decoded=(offset, 1, 0),
2301 return pp_console_row(next(self.pps()))
2303 def pps(self, decode_path=()):
2305 asn1_type_name=self.asn1_type_name,
2306 obj_name=self.__class__.__name__,
2307 decode_path=decode_path,
2308 optional=self.optional,
2309 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2310 expl=None if self._expl is None else tag_decode(self._expl),
2315 expl_offset=self.expl_offset if self.expled else None,
2316 expl_tlen=self.expl_tlen if self.expled else None,
2317 expl_llen=self.expl_llen if self.expled else None,
2318 expl_vlen=self.expl_vlen if self.expled else None,
2322 class ObjectIdentifier(Obj):
2323 """``OBJECT IDENTIFIER`` OID type
2325 >>> oid = ObjectIdentifier((1, 2, 3))
2326 OBJECT IDENTIFIER 1.2.3
2327 >>> oid == ObjectIdentifier("1.2.3")
2333 >>> oid + (4, 5) + ObjectIdentifier("1.7")
2334 OBJECT IDENTIFIER 1.2.3.4.5.1.7
2336 >>> str(ObjectIdentifier((3, 1)))
2337 Traceback (most recent call last):
2338 pyderasn.InvalidOID: unacceptable first arc value
2340 __slots__ = ("defines",)
2341 tag_default = tag_encode(6)
2342 asn1_type_name = "OBJECT IDENTIFIER"
2355 :param value: set the value. Either tuples of integers,
2356 string of "."-concatenated integers, or
2357 :py:class:`pyderasn.ObjectIdentifier` object
2358 :param defines: tuple of two elements. First one is a name of
2359 field inside :py:class:`pyderasn.Sequence`,
2360 defining with that OID. Second element is a
2361 ``{OID: pyderasn.Obj()}`` dictionary, mapping
2362 between current OID value and structure applied
2364 :ref:`Read about DEFINED BY <definedby>`
2365 :param bytes impl: override default tag with ``IMPLICIT`` one
2366 :param bytes expl: override default tag with ``EXPLICIT`` one
2367 :param default: set default value. Type same as in ``value``
2368 :param bool optional: is object ``OPTIONAL`` in sequence
2370 super(ObjectIdentifier, self).__init__(
2378 if value is not None:
2379 self._value = self._value_sanitize(value)
2380 if default is not None:
2381 default = self._value_sanitize(default)
2382 self.default = self.__class__(
2387 if self._value is None:
2388 self._value = default
2389 self.defines = defines
2391 def __add__(self, their):
2392 if isinstance(their, self.__class__):
2393 return self.__class__(self._value + their._value)
2394 if isinstance(their, tuple):
2395 return self.__class__(self._value + their)
2396 raise InvalidValueType((self.__class__, tuple))
2398 def _value_sanitize(self, value):
2399 if issubclass(value.__class__, ObjectIdentifier):
2401 if isinstance(value, string_types):
2403 value = tuple(int(arc) for arc in value.split("."))
2405 raise InvalidOID("unacceptable arcs values")
2406 if isinstance(value, tuple):
2408 raise InvalidOID("less than 2 arcs")
2409 first_arc = value[0]
2410 if first_arc in (0, 1):
2411 if not (0 <= value[1] <= 39):
2412 raise InvalidOID("second arc is too wide")
2413 elif first_arc == 2:
2416 raise InvalidOID("unacceptable first arc value")
2418 raise InvalidValueType((self.__class__, str, tuple))
2422 return self._value is not None
2425 obj = self.__class__()
2426 obj._value = self._value
2427 obj.defines = self.defines
2429 obj._expl = self._expl
2430 obj.default = self.default
2431 obj.optional = self.optional
2432 obj.offset = self.offset
2433 obj.llen = self.llen
2434 obj.vlen = self.vlen
2438 self._assert_ready()
2439 return iter(self._value)
2442 return ".".join(str(arc) for arc in self._value or ())
2445 self._assert_ready()
2448 bytes(self._expl or b"") +
2449 str(self._value).encode("ascii"),
2452 def __eq__(self, their):
2453 if isinstance(their, tuple):
2454 return self._value == their
2455 if not issubclass(their.__class__, ObjectIdentifier):
2458 self.tag == their.tag and
2459 self._expl == their._expl and
2460 self._value == their._value
2463 def __lt__(self, their):
2464 return self._value < their._value
2475 return self.__class__(
2477 defines=self.defines if defines is None else defines,
2478 impl=self.tag if impl is None else impl,
2479 expl=self._expl if expl is None else expl,
2480 default=self.default if default is None else default,
2481 optional=self.optional if optional is None else optional,
2485 self._assert_ready()
2487 first_value = value[1]
2488 first_arc = value[0]
2491 elif first_arc == 1:
2493 elif first_arc == 2:
2495 else: # pragma: no cover
2496 raise RuntimeError("invalid arc is stored")
2497 octets = [zero_ended_encode(first_value)]
2498 for arc in value[2:]:
2499 octets.append(zero_ended_encode(arc))
2500 v = b"".join(octets)
2501 return b"".join((self.tag, len_encode(len(v)), v))
2503 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
2505 t, _, lv = tag_strip(tlv)
2506 except DecodeError as err:
2507 raise err.__class__(
2509 klass=self.__class__,
2510 decode_path=decode_path,
2515 klass=self.__class__,
2516 decode_path=decode_path,
2520 l, llen, v = len_decode(lv)
2521 except DecodeError as err:
2522 raise err.__class__(
2524 klass=self.__class__,
2525 decode_path=decode_path,
2529 raise NotEnoughData(
2530 "encoded length is longer than data",
2531 klass=self.__class__,
2532 decode_path=decode_path,
2536 raise NotEnoughData(
2538 klass=self.__class__,
2539 decode_path=decode_path,
2542 v, tail = v[:l], v[l:]
2548 octet = indexbytes(v, i)
2549 arc = (arc << 7) | (octet & 0x7F)
2550 if octet & 0x80 == 0:
2558 klass=self.__class__,
2559 decode_path=decode_path,
2563 second_arc = arcs[0]
2564 if 0 <= second_arc <= 39:
2566 elif 40 <= second_arc <= 79:
2572 obj = self.__class__(
2573 value=tuple([first_arc, second_arc] + arcs[1:]),
2576 default=self.default,
2577 optional=self.optional,
2578 _decoded=(offset, llen, l),
2583 return pp_console_row(next(self.pps()))
2585 def pps(self, decode_path=()):
2587 asn1_type_name=self.asn1_type_name,
2588 obj_name=self.__class__.__name__,
2589 decode_path=decode_path,
2590 value=str(self) if self.ready else None,
2591 optional=self.optional,
2592 default=self == self.default,
2593 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2594 expl=None if self._expl is None else tag_decode(self._expl),
2599 expl_offset=self.expl_offset if self.expled else None,
2600 expl_tlen=self.expl_tlen if self.expled else None,
2601 expl_llen=self.expl_llen if self.expled else None,
2602 expl_vlen=self.expl_vlen if self.expled else None,
2606 class Enumerated(Integer):
2607 """``ENUMERATED`` integer type
2609 This type is identical to :py:class:`pyderasn.Integer`, but requires
2610 schema to be specified and does not accept values missing from it.
2613 tag_default = tag_encode(10)
2614 asn1_type_name = "ENUMERATED"
2625 bounds=None, # dummy argument, workability for Integer.decode
2627 super(Enumerated, self).__init__(
2636 if len(self.specs) == 0:
2637 raise ValueError("schema must be specified")
2639 def _value_sanitize(self, value):
2640 if isinstance(value, self.__class__):
2641 value = value._value
2642 elif isinstance(value, integer_types):
2643 if value not in list(self.specs.values()):
2645 "unknown integer value: %s" % value,
2646 klass=self.__class__,
2648 elif isinstance(value, string_types):
2649 value = self.specs.get(value)
2651 raise ObjUnknown("integer value: %s" % value)
2653 raise InvalidValueType((self.__class__, int, str))
2657 obj = self.__class__(_specs=self.specs)
2658 obj._value = self._value
2659 obj._bound_min = self._bound_min
2660 obj._bound_max = self._bound_max
2662 obj._expl = self._expl
2663 obj.default = self.default
2664 obj.optional = self.optional
2665 obj.offset = self.offset
2666 obj.llen = self.llen
2667 obj.vlen = self.vlen
2679 return self.__class__(
2681 impl=self.tag if impl is None else impl,
2682 expl=self._expl if expl is None else expl,
2683 default=self.default if default is None else default,
2684 optional=self.optional if optional is None else optional,
2689 class CommonString(OctetString):
2690 """Common class for all strings
2692 Everything resembles :py:class:`pyderasn.OctetString`, except
2693 ability to deal with unicode text strings.
2695 >>> hexenc("привет мир".encode("utf-8"))
2696 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
2697 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
2699 >>> s = UTF8String("привет мир")
2700 UTF8String UTF8String привет мир
2702 'привет мир'
2703 >>> hexenc(bytes(s))
2704 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
2706 >>> PrintableString("привет мир")
2707 Traceback (most recent call last):
2708 UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
2710 >>> BMPString("ада", bounds=(2, 2))
2711 Traceback (most recent call last):
2712 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
2713 >>> s = BMPString("ад", bounds=(2, 2))
2716 >>> hexenc(bytes(s))
2724 * - :py:class:`pyderasn.UTF8String`
2726 * - :py:class:`pyderasn.NumericString`
2728 * - :py:class:`pyderasn.PrintableString`
2730 * - :py:class:`pyderasn.TeletexString`
2732 * - :py:class:`pyderasn.T61String`
2734 * - :py:class:`pyderasn.VideotexString`
2736 * - :py:class:`pyderasn.IA5String`
2738 * - :py:class:`pyderasn.GraphicString`
2740 * - :py:class:`pyderasn.VisibleString`
2742 * - :py:class:`pyderasn.ISO646String`
2744 * - :py:class:`pyderasn.GeneralString`
2746 * - :py:class:`pyderasn.UniversalString`
2748 * - :py:class:`pyderasn.BMPString`
2751 __slots__ = ("encoding",)
2753 def _value_sanitize(self, value):
2755 value_decoded = None
2756 if isinstance(value, self.__class__):
2757 value_raw = value._value
2758 elif isinstance(value, text_type):
2759 value_decoded = value
2760 elif isinstance(value, binary_type):
2763 raise InvalidValueType((self.__class__, text_type, binary_type))
2765 value_decoded.encode(self.encoding)
2766 if value_raw is None else value_raw
2769 value_raw.decode(self.encoding)
2770 if value_decoded is None else value_decoded
2772 if not self._bound_min <= len(value_decoded) <= self._bound_max:
2780 def __eq__(self, their):
2781 if isinstance(their, binary_type):
2782 return self._value == their
2783 if isinstance(their, text_type):
2784 return self._value == their.encode(self.encoding)
2785 if not isinstance(their, self.__class__):
2788 self._value == their._value and
2789 self.tag == their.tag and
2790 self._expl == their._expl
2793 def __unicode__(self):
2795 return self._value.decode(self.encoding)
2796 return text_type(self._value)
2799 return pp_console_row(next(self.pps(no_unicode=PY2)))
2801 def pps(self, decode_path=(), no_unicode=False):
2804 value = hexenc(bytes(self)) if no_unicode else self.__unicode__()
2806 asn1_type_name=self.asn1_type_name,
2807 obj_name=self.__class__.__name__,
2808 decode_path=decode_path,
2810 optional=self.optional,
2811 default=self == self.default,
2812 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2813 expl=None if self._expl is None else tag_decode(self._expl),
2821 class UTF8String(CommonString):
2823 tag_default = tag_encode(12)
2825 asn1_type_name = "UTF8String"
2828 class NumericString(CommonString):
2830 tag_default = tag_encode(18)
2832 asn1_type_name = "NumericString"
2835 class PrintableString(CommonString):
2837 tag_default = tag_encode(19)
2839 asn1_type_name = "PrintableString"
2842 class TeletexString(CommonString):
2844 tag_default = tag_encode(20)
2846 asn1_type_name = "TeletexString"
2849 class T61String(TeletexString):
2851 asn1_type_name = "T61String"
2854 class VideotexString(CommonString):
2856 tag_default = tag_encode(21)
2857 encoding = "iso-8859-1"
2858 asn1_type_name = "VideotexString"
2861 class IA5String(CommonString):
2863 tag_default = tag_encode(22)
2865 asn1_type_name = "IA5"
2868 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
2869 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
2870 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
2873 class UTCTime(CommonString):
2874 """``UTCTime`` datetime type
2876 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
2877 UTCTime UTCTime 2017-09-30T22:07:50
2883 datetime.datetime(2017, 9, 30, 22, 7, 50)
2884 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
2885 datetime.datetime(1957, 9, 30, 22, 7, 50)
2888 tag_default = tag_encode(23)
2890 asn1_type_name = "UTCTime"
2892 fmt = "%y%m%d%H%M%SZ"
2902 bounds=None, # dummy argument, workability for OctetString.decode
2905 :param value: set the value. Either datetime type, or
2906 :py:class:`pyderasn.UTCTime` object
2907 :param bytes impl: override default tag with ``IMPLICIT`` one
2908 :param bytes expl: override default tag with ``EXPLICIT`` one
2909 :param default: set default value. Type same as in ``value``
2910 :param bool optional: is object ``OPTIONAL`` in sequence
2912 super(UTCTime, self).__init__(
2920 if value is not None:
2921 self._value = self._value_sanitize(value)
2922 if default is not None:
2923 default = self._value_sanitize(default)
2924 self.default = self.__class__(
2929 if self._value is None:
2930 self._value = default
2932 def _value_sanitize(self, value):
2933 if isinstance(value, self.__class__):
2935 if isinstance(value, datetime):
2936 return value.strftime(self.fmt).encode("ascii")
2937 if isinstance(value, binary_type):
2938 value_decoded = value.decode("ascii")
2939 if len(value_decoded) == LEN_YYMMDDHHMMSSZ:
2941 datetime.strptime(value_decoded, self.fmt)
2943 raise DecodeError("invalid UTCTime format")
2946 raise DecodeError("invalid UTCTime length")
2947 raise InvalidValueType((self.__class__, datetime))
2949 def __eq__(self, their):
2950 if isinstance(their, binary_type):
2951 return self._value == their
2952 if isinstance(their, datetime):
2953 return self.todatetime() == their
2954 if not isinstance(their, self.__class__):
2957 self._value == their._value and
2958 self.tag == their.tag and
2959 self._expl == their._expl
2962 def todatetime(self):
2963 """Convert to datetime
2967 Pay attention that UTCTime can not hold full year, so all years
2968 having < 50 years are treated as 20xx, 19xx otherwise, according
2969 to X.509 recomendation.
2971 value = datetime.strptime(self._value.decode("ascii"), self.fmt)
2972 year = value.year % 100
2974 year=(2000 + year) if year < 50 else (1900 + year),
2978 minute=value.minute,
2979 second=value.second,
2983 return pp_console_row(next(self.pps()))
2985 def pps(self, decode_path=()):
2987 asn1_type_name=self.asn1_type_name,
2988 obj_name=self.__class__.__name__,
2989 decode_path=decode_path,
2990 value=self.todatetime().isoformat() if self.ready else None,
2991 optional=self.optional,
2992 default=self == self.default,
2993 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2994 expl=None if self._expl is None else tag_decode(self._expl),
3002 class GeneralizedTime(UTCTime):
3003 """``GeneralizedTime`` datetime type
3005 This type is similar to :py:class:`pyderasn.UTCTime`.
3007 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3008 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
3010 '20170930220750.000123Z'
3011 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
3012 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
3015 tag_default = tag_encode(24)
3016 asn1_type_name = "GeneralizedTime"
3018 fmt = "%Y%m%d%H%M%SZ"
3019 fmt_ms = "%Y%m%d%H%M%S.%fZ"
3021 def _value_sanitize(self, value):
3022 if isinstance(value, self.__class__):
3024 if isinstance(value, datetime):
3025 return value.strftime(
3026 self.fmt_ms if value.microsecond > 0 else self.fmt
3028 if isinstance(value, binary_type):
3029 value_decoded = value.decode("ascii")
3030 if len(value_decoded) == LEN_YYYYMMDDHHMMSSZ:
3032 datetime.strptime(value_decoded, self.fmt)
3035 "invalid GeneralizedTime (without ms) format",
3038 elif len(value_decoded) >= LEN_YYYYMMDDHHMMSSDMZ:
3040 datetime.strptime(value_decoded, self.fmt_ms)
3043 "invalid GeneralizedTime (with ms) format",
3048 "invalid GeneralizedTime length",
3049 klass=self.__class__,
3051 raise InvalidValueType((self.__class__, datetime))
3053 def todatetime(self):
3054 value = self._value.decode("ascii")
3055 if len(value) == LEN_YYYYMMDDHHMMSSZ:
3056 return datetime.strptime(value, self.fmt)
3057 return datetime.strptime(value, self.fmt_ms)
3060 class GraphicString(CommonString):
3062 tag_default = tag_encode(25)
3063 encoding = "iso-8859-1"
3064 asn1_type_name = "GraphicString"
3067 class VisibleString(CommonString):
3069 tag_default = tag_encode(26)
3071 asn1_type_name = "VisibleString"
3074 class ISO646String(VisibleString):
3076 asn1_type_name = "ISO646String"
3079 class GeneralString(CommonString):
3081 tag_default = tag_encode(27)
3082 encoding = "iso-8859-1"
3083 asn1_type_name = "GeneralString"
3086 class UniversalString(CommonString):
3088 tag_default = tag_encode(28)
3089 encoding = "utf-32-be"
3090 asn1_type_name = "UniversalString"
3093 class BMPString(CommonString):
3095 tag_default = tag_encode(30)
3096 encoding = "utf-16-be"
3097 asn1_type_name = "BMPString"
3101 """``CHOICE`` special type
3105 class GeneralName(Choice):
3107 ('rfc822Name', IA5String(impl=tag_ctxp(1))),
3108 ('dNSName', IA5String(impl=tag_ctxp(2))),
3111 >>> gn = GeneralName()
3113 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
3114 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3115 >>> gn["dNSName"] = IA5String("bar.baz")
3116 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
3117 >>> gn["rfc822Name"]
3120 [2] IA5String IA5 bar.baz
3123 >>> gn.value == gn["dNSName"]
3126 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
3128 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
3129 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3131 __slots__ = ("specs",)
3133 asn1_type_name = "CHOICE"
3146 :param value: set the value. Either ``(choice, value)`` tuple, or
3147 :py:class:`pyderasn.Choice` object
3148 :param bytes impl: can not be set, do **not** use it
3149 :param bytes expl: override default tag with ``EXPLICIT`` one
3150 :param default: set default value. Type same as in ``value``
3151 :param bool optional: is object ``OPTIONAL`` in sequence
3153 if impl is not None:
3154 raise ValueError("no implicit tag allowed for CHOICE")
3155 super(Choice, self).__init__(None, expl, default, optional, _decoded)
3157 schema = getattr(self, "schema", ())
3158 if len(schema) == 0:
3159 raise ValueError("schema must be specified")
3161 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
3164 if value is not None:
3165 self._value = self._value_sanitize(value)
3166 if default is not None:
3167 default_value = self._value_sanitize(default)
3168 default_obj = self.__class__(impl=self.tag, expl=self._expl)
3169 default_obj.specs = self.specs
3170 default_obj._value = default_value
3171 self.default = default_obj
3173 self._value = default_obj.copy()._value
3175 def _value_sanitize(self, value):
3176 if isinstance(value, self.__class__):
3178 if isinstance(value, tuple) and len(value) == 2:
3180 spec = self.specs.get(choice)
3182 raise ObjUnknown(choice)
3183 if not isinstance(obj, spec.__class__):
3184 raise InvalidValueType((spec,))
3185 return (choice, spec(obj))
3186 raise InvalidValueType((self.__class__, tuple))
3190 return self._value is not None and self._value[1].ready
3193 obj = self.__class__(schema=self.specs)
3194 obj._expl = self._expl
3195 obj.default = self.default
3196 obj.optional = self.optional
3197 obj.offset = self.offset
3198 obj.llen = self.llen
3199 obj.vlen = self.vlen
3201 if value is not None:
3202 obj._value = (value[0], value[1].copy())
3205 def __eq__(self, their):
3206 if isinstance(their, tuple) and len(their) == 2:
3207 return self._value == their
3208 if not isinstance(their, self.__class__):
3211 self.specs == their.specs and
3212 self._value == their._value
3222 return self.__class__(
3225 expl=self._expl if expl is None else expl,
3226 default=self.default if default is None else default,
3227 optional=self.optional if optional is None else optional,
3232 self._assert_ready()
3233 return self._value[0]
3237 self._assert_ready()
3238 return self._value[1]
3240 def __getitem__(self, key):
3241 if key not in self.specs:
3242 raise ObjUnknown(key)
3243 if self._value is None:
3245 choice, value = self._value
3250 def __setitem__(self, key, value):
3251 spec = self.specs.get(key)
3253 raise ObjUnknown(key)
3254 if not isinstance(value, spec.__class__):
3255 raise InvalidValueType((spec.__class__,))
3256 self._value = (key, spec(value))
3264 return self._value[1].decoded if self.ready else False
3267 self._assert_ready()
3268 return self._value[1].encode()
3270 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
3271 for choice, spec in self.specs.items():
3273 value, tail = spec.decode(
3277 decode_path=decode_path + (choice,),
3278 defines_by_path=defines_by_path,
3282 obj = self.__class__(
3285 default=self.default,
3286 optional=self.optional,
3287 _decoded=(offset, 0, value.tlvlen),
3289 obj._value = (choice, value)
3292 klass=self.__class__,
3293 decode_path=decode_path,
3298 value = pp_console_row(next(self.pps()))
3300 value = "%s[%r]" % (value, self.value)
3303 def pps(self, decode_path=()):
3305 asn1_type_name=self.asn1_type_name,
3306 obj_name=self.__class__.__name__,
3307 decode_path=decode_path,
3308 value=self.choice if self.ready else None,
3309 optional=self.optional,
3310 default=self == self.default,
3311 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3312 expl=None if self._expl is None else tag_decode(self._expl),
3319 yield self.value.pps(decode_path=decode_path + (self.choice,))
3322 class PrimitiveTypes(Choice):
3323 """Predefined ``CHOICE`` for all generic primitive types
3325 It could be useful for general decoding of some unspecified values:
3327 >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
3328 OCTET STRING 3 bytes 666f6f
3329 >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
3333 schema = tuple((klass.__name__, klass()) for klass in (
3358 """``ANY`` special type
3360 >>> Any(Integer(-123))
3362 >>> a = Any(OctetString(b"hello world").encode())
3363 ANY 040b68656c6c6f20776f726c64
3364 >>> hexenc(bytes(a))
3365 b'0x040x0bhello world'
3367 __slots__ = ("defined",)
3368 tag_default = tag_encode(0)
3369 asn1_type_name = "ANY"
3379 :param value: set the value. Either any kind of pyderasn's
3380 **ready** object, or bytes. Pay attention that
3381 **no** validation is performed is raw binary value
3383 :param bytes expl: override default tag with ``EXPLICIT`` one
3384 :param bool optional: is object ``OPTIONAL`` in sequence
3386 super(Any, self).__init__(None, expl, None, optional, _decoded)
3387 self._value = None if value is None else self._value_sanitize(value)
3390 def _value_sanitize(self, value):
3391 if isinstance(value, self.__class__):
3393 if isinstance(value, Obj):
3394 return value.encode()
3395 if isinstance(value, binary_type):
3397 raise InvalidValueType((self.__class__, Obj, binary_type))
3401 return self._value is not None
3404 obj = self.__class__()
3405 obj._value = self._value
3407 obj._expl = self._expl
3408 obj.optional = self.optional
3409 obj.offset = self.offset
3410 obj.llen = self.llen
3411 obj.vlen = self.vlen
3414 def __eq__(self, their):
3415 if isinstance(their, binary_type):
3416 return self._value == their
3417 if issubclass(their.__class__, Any):
3418 return self._value == their._value
3427 return self.__class__(
3429 expl=self._expl if expl is None else expl,
3430 optional=self.optional if optional is None else optional,
3433 def __bytes__(self):
3434 self._assert_ready()
3442 self._assert_ready()
3445 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
3447 t, tlen, lv = tag_strip(tlv)
3448 l, llen, v = len_decode(lv)
3449 except DecodeError as err:
3450 raise err.__class__(
3452 klass=self.__class__,
3453 decode_path=decode_path,
3457 raise NotEnoughData(
3458 "encoded length is longer than data",
3459 klass=self.__class__,
3460 decode_path=decode_path,
3463 tlvlen = tlen + llen + l
3464 v, tail = tlv[:tlvlen], v[l:]
3465 obj = self.__class__(
3468 optional=self.optional,
3469 _decoded=(offset, 0, tlvlen),
3475 return pp_console_row(next(self.pps()))
3477 def pps(self, decode_path=()):
3479 asn1_type_name=self.asn1_type_name,
3480 obj_name=self.__class__.__name__,
3481 decode_path=decode_path,
3482 blob=self._value if self.ready else None,
3483 optional=self.optional,
3484 default=self == self.default,
3485 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3486 expl=None if self._expl is None else tag_decode(self._expl),
3491 expl_offset=self.expl_offset if self.expled else None,
3492 expl_tlen=self.expl_tlen if self.expled else None,
3493 expl_llen=self.expl_llen if self.expled else None,
3494 expl_vlen=self.expl_vlen if self.expled else None,
3496 defined_by, defined = self.defined or (None, None)
3497 if defined_by is not None:
3499 decode_path=decode_path + (decode_path_defby(defined_by),)
3503 ########################################################################
3504 # ASN.1 constructed types
3505 ########################################################################
3507 def get_def_by_path(defines_by_path, sub_decode_path):
3508 """Get define by decode path
3510 for path, define in defines_by_path:
3511 if len(path) != len(sub_decode_path):
3513 for p1, p2 in zip(path, sub_decode_path):
3514 if (p1 != any) and (p1 != p2):
3520 class Sequence(Obj):
3521 """``SEQUENCE`` structure type
3523 You have to make specification of sequence::
3525 class Extension(Sequence):
3527 ("extnID", ObjectIdentifier()),
3528 ("critical", Boolean(default=False)),
3529 ("extnValue", OctetString()),
3532 Then, you can work with it as with dictionary.
3534 >>> ext = Extension()
3535 >>> Extension().specs
3537 ('extnID', OBJECT IDENTIFIER),
3538 ('critical', BOOLEAN False OPTIONAL DEFAULT),
3539 ('extnValue', OCTET STRING),
3541 >>> ext["extnID"] = "1.2.3"
3542 Traceback (most recent call last):
3543 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
3544 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
3546 You can know if sequence is ready to be encoded:
3551 Traceback (most recent call last):
3552 pyderasn.ObjNotReady: object is not ready: extnValue
3553 >>> ext["extnValue"] = OctetString(b"foobar")
3557 Value you want to assign, must have the same **type** as in
3558 corresponding specification, but it can have different tags,
3559 optional/default attributes -- they will be taken from specification
3562 class TBSCertificate(Sequence):
3564 ("version", Version(expl=tag_ctxc(0), default="v1")),
3567 >>> tbs = TBSCertificate()
3568 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
3570 You can know if value exists/set in the sequence and take its value:
3572 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
3575 OBJECT IDENTIFIER 1.2.3
3577 But pay attention that if value has default, then it won't be (not
3578 in) in the sequence (because ``DEFAULT`` must not be encoded in
3579 DER), but you can read its value:
3581 >>> "critical" in ext, ext["critical"]
3582 (False, BOOLEAN False)
3583 >>> ext["critical"] = Boolean(True)
3584 >>> "critical" in ext, ext["critical"]
3585 (True, BOOLEAN True)
3587 All defaulted values are always optional.
3591 When decoded DER contains defaulted value inside, then
3592 technically this is not valid DER encoding. But we allow
3593 and pass it. Of course reencoding of that kind of DER will
3594 result in different binary representation (validly without
3595 defaulted value inside).
3597 Two sequences are equal if they have equal specification (schema),
3598 implicit/explicit tagging and the same values.
3600 __slots__ = ("specs",)
3601 tag_default = tag_encode(form=TagFormConstructed, num=16)
3602 asn1_type_name = "SEQUENCE"
3614 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
3616 schema = getattr(self, "schema", ())
3618 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
3621 if value is not None:
3622 self._value = self._value_sanitize(value)
3623 if default is not None:
3624 default_value = self._value_sanitize(default)
3625 default_obj = self.__class__(impl=self.tag, expl=self._expl)
3626 default_obj.specs = self.specs
3627 default_obj._value = default_value
3628 self.default = default_obj
3630 self._value = default_obj.copy()._value
3632 def _value_sanitize(self, value):
3633 if not issubclass(value.__class__, Sequence):
3634 raise InvalidValueType((Sequence,))
3639 for name, spec in self.specs.items():
3640 value = self._value.get(name)
3651 obj = self.__class__(schema=self.specs)
3653 obj._expl = self._expl
3654 obj.default = self.default
3655 obj.optional = self.optional
3656 obj.offset = self.offset
3657 obj.llen = self.llen
3658 obj.vlen = self.vlen
3659 obj._value = {k: v.copy() for k, v in self._value.items()}
3662 def __eq__(self, their):
3663 if not isinstance(their, self.__class__):
3666 self.specs == their.specs and
3667 self.tag == their.tag and
3668 self._expl == their._expl and
3669 self._value == their._value
3680 return self.__class__(
3683 impl=self.tag if impl is None else impl,
3684 expl=self._expl if expl is None else expl,
3685 default=self.default if default is None else default,
3686 optional=self.optional if optional is None else optional,
3689 def __contains__(self, key):
3690 return key in self._value
3692 def __setitem__(self, key, value):
3693 spec = self.specs.get(key)
3695 raise ObjUnknown(key)
3697 self._value.pop(key, None)
3699 if not isinstance(value, spec.__class__):
3700 raise InvalidValueType((spec.__class__,))
3701 value = spec(value=value)
3702 if spec.default is not None and value == spec.default:
3703 self._value.pop(key, None)
3705 self._value[key] = value
3707 def __getitem__(self, key):
3708 value = self._value.get(key)
3709 if value is not None:
3711 spec = self.specs.get(key)
3713 raise ObjUnknown(key)
3714 if spec.default is not None:
3718 def _encoded_values(self):
3720 for name, spec in self.specs.items():
3721 value = self._value.get(name)
3725 raise ObjNotReady(name)
3726 raws.append(value.encode())
3730 v = b"".join(self._encoded_values())
3731 return b"".join((self.tag, len_encode(len(v)), v))
3733 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
3735 t, tlen, lv = tag_strip(tlv)
3736 except DecodeError as err:
3737 raise err.__class__(
3739 klass=self.__class__,
3740 decode_path=decode_path,
3745 klass=self.__class__,
3746 decode_path=decode_path,
3750 l, llen, v = len_decode(lv)
3751 except DecodeError as err:
3752 raise err.__class__(
3754 klass=self.__class__,
3755 decode_path=decode_path,
3759 raise NotEnoughData(
3760 "encoded length is longer than data",
3761 klass=self.__class__,
3762 decode_path=decode_path,
3765 v, tail = v[:l], v[l:]
3766 sub_offset = offset + tlen + llen
3769 for name, spec in self.specs.items():
3770 if len(v) == 0 and spec.optional:
3772 sub_decode_path = decode_path + (name,)
3774 value, v_tail = spec.decode(
3778 decode_path=sub_decode_path,
3779 defines_by_path=defines_by_path,
3786 defined = defines.pop(name, None)
3787 if defined is not None:
3788 defined_by, defined_spec = defined
3789 if issubclass(value.__class__, SequenceOf):
3790 for i, _value in enumerate(value):
3791 sub_sub_decode_path = sub_decode_path + (
3793 decode_path_defby(defined_by),
3795 defined_value, defined_tail = defined_spec.decode(
3796 memoryview(bytes(_value)),
3797 sub_offset + value.tlen + value.llen,
3799 decode_path=sub_sub_decode_path,
3800 defines_by_path=defines_by_path,
3802 if len(defined_tail) > 0:
3805 klass=self.__class__,
3806 decode_path=sub_sub_decode_path,
3809 _value.defined = (defined_by, defined_value)
3811 defined_value, defined_tail = defined_spec.decode(
3812 memoryview(bytes(value)),
3813 sub_offset + value.tlen + value.llen,
3815 decode_path=sub_decode_path + (decode_path_defby(defined_by),),
3816 defines_by_path=defines_by_path,
3818 if len(defined_tail) > 0:
3821 klass=self.__class__,
3822 decode_path=sub_decode_path + (decode_path_defby(defined_by),),
3825 value.defined = (defined_by, defined_value)
3827 sub_offset += (value.expl_tlvlen if value.expled else value.tlvlen)
3829 if spec.default is not None and value == spec.default:
3830 # Encoded default values are not valid in DER,
3831 # but we allow that anyway
3833 values[name] = value
3835 spec_defines = getattr(spec, "defines", None)
3836 if defines_by_path is not None and spec_defines is None:
3837 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
3838 if spec_defines is not None:
3839 what, schema = spec_defines
3840 defined = schema.get(value, None)
3841 if defined is not None:
3842 defines[what] = (value, defined)
3846 klass=self.__class__,
3847 decode_path=decode_path,
3850 obj = self.__class__(
3854 default=self.default,
3855 optional=self.optional,
3856 _decoded=(offset, llen, l),
3862 value = pp_console_row(next(self.pps()))
3864 for name in self.specs:
3865 _value = self._value.get(name)
3868 cols.append(repr(_value))
3869 return "%s[%s]" % (value, ", ".join(cols))
3871 def pps(self, decode_path=()):
3873 asn1_type_name=self.asn1_type_name,
3874 obj_name=self.__class__.__name__,
3875 decode_path=decode_path,
3876 optional=self.optional,
3877 default=self == self.default,
3878 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3879 expl=None if self._expl is None else tag_decode(self._expl),
3884 expl_offset=self.expl_offset if self.expled else None,
3885 expl_tlen=self.expl_tlen if self.expled else None,
3886 expl_llen=self.expl_llen if self.expled else None,
3887 expl_vlen=self.expl_vlen if self.expled else None,
3889 for name in self.specs:
3890 value = self._value.get(name)
3893 yield value.pps(decode_path=decode_path + (name,))
3896 class Set(Sequence):
3897 """``SET`` structure type
3899 Its usage is identical to :py:class:`pyderasn.Sequence`.
3902 tag_default = tag_encode(form=TagFormConstructed, num=17)
3903 asn1_type_name = "SET"
3906 raws = self._encoded_values()
3909 return b"".join((self.tag, len_encode(len(v)), v))
3911 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
3913 t, tlen, lv = tag_strip(tlv)
3914 except DecodeError as err:
3915 raise err.__class__(
3917 klass=self.__class__,
3918 decode_path=decode_path,
3923 klass=self.__class__,
3924 decode_path=decode_path,
3928 l, llen, v = len_decode(lv)
3929 except DecodeError as err:
3930 raise err.__class__(
3932 klass=self.__class__,
3933 decode_path=decode_path,
3937 raise NotEnoughData(
3938 "encoded length is longer than data",
3939 klass=self.__class__,
3942 v, tail = v[:l], v[l:]
3943 sub_offset = offset + tlen + llen
3945 specs_items = self.specs.items
3947 for name, spec in specs_items():
3949 value, v_tail = spec.decode(
3953 decode_path=decode_path + (name,),
3954 defines_by_path=defines_by_path,
3959 value.expl_tlvlen if value.expled else value.tlvlen
3962 if spec.default is None or value != spec.default: # pragma: no cover
3963 # SeqMixing.test_encoded_default_accepted covers that place
3964 values[name] = value
3968 klass=self.__class__,
3969 decode_path=decode_path,
3972 obj = self.__class__(
3976 default=self.default,
3977 optional=self.optional,
3978 _decoded=(offset, llen, l),
3984 class SequenceOf(Obj):
3985 """``SEQUENCE OF`` sequence type
3987 For that kind of type you must specify the object it will carry on
3988 (bounds are for example here, not required)::
3990 class Ints(SequenceOf):
3995 >>> ints.append(Integer(123))
3996 >>> ints.append(Integer(234))
3998 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
3999 >>> [int(i) for i in ints]
4001 >>> ints.append(Integer(345))
4002 Traceback (most recent call last):
4003 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
4006 >>> ints[1] = Integer(345)
4008 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
4010 Also you can initialize sequence with preinitialized values:
4012 >>> ints = Ints([Integer(123), Integer(234)])
4014 __slots__ = ("spec", "_bound_min", "_bound_max")
4015 tag_default = tag_encode(form=TagFormConstructed, num=16)
4016 asn1_type_name = "SEQUENCE OF"
4029 super(SequenceOf, self).__init__(
4037 schema = getattr(self, "schema", None)
4039 raise ValueError("schema must be specified")
4041 self._bound_min, self._bound_max = getattr(
4045 ) if bounds is None else bounds
4047 if value is not None:
4048 self._value = self._value_sanitize(value)
4049 if default is not None:
4050 default_value = self._value_sanitize(default)
4051 default_obj = self.__class__(
4056 default_obj._value = default_value
4057 self.default = default_obj
4059 self._value = default_obj.copy()._value
4061 def _value_sanitize(self, value):
4062 if issubclass(value.__class__, SequenceOf):
4063 value = value._value
4064 elif hasattr(value, "__iter__"):
4067 raise InvalidValueType((self.__class__, iter))
4068 if not self._bound_min <= len(value) <= self._bound_max:
4069 raise BoundsError(self._bound_min, len(value), self._bound_max)
4071 if not isinstance(v, self.spec.__class__):
4072 raise InvalidValueType((self.spec.__class__,))
4077 return all(v.ready for v in self._value)
4080 obj = self.__class__(schema=self.spec)
4081 obj._bound_min = self._bound_min
4082 obj._bound_max = self._bound_max
4084 obj._expl = self._expl
4085 obj.default = self.default
4086 obj.optional = self.optional
4087 obj.offset = self.offset
4088 obj.llen = self.llen
4089 obj.vlen = self.vlen
4090 obj._value = [v.copy() for v in self._value]
4093 def __eq__(self, their):
4094 if isinstance(their, self.__class__):
4096 self.spec == their.spec and
4097 self.tag == their.tag and
4098 self._expl == their._expl and
4099 self._value == their._value
4101 if hasattr(their, "__iter__"):
4102 return self._value == list(their)
4114 return self.__class__(
4118 (self._bound_min, self._bound_max)
4119 if bounds is None else bounds
4121 impl=self.tag if impl is None else impl,
4122 expl=self._expl if expl is None else expl,
4123 default=self.default if default is None else default,
4124 optional=self.optional if optional is None else optional,
4127 def __contains__(self, key):
4128 return key in self._value
4130 def append(self, value):
4131 if not isinstance(value, self.spec.__class__):
4132 raise InvalidValueType((self.spec.__class__,))
4133 if len(self._value) + 1 > self._bound_max:
4136 len(self._value) + 1,
4139 self._value.append(value)
4142 self._assert_ready()
4143 return iter(self._value)
4146 self._assert_ready()
4147 return len(self._value)
4149 def __setitem__(self, key, value):
4150 if not isinstance(value, self.spec.__class__):
4151 raise InvalidValueType((self.spec.__class__,))
4152 self._value[key] = self.spec(value=value)
4154 def __getitem__(self, key):
4155 return self._value[key]
4157 def _encoded_values(self):
4158 return [v.encode() for v in self._value]
4161 v = b"".join(self._encoded_values())
4162 return b"".join((self.tag, len_encode(len(v)), v))
4164 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
4166 t, tlen, lv = tag_strip(tlv)
4167 except DecodeError as err:
4168 raise err.__class__(
4170 klass=self.__class__,
4171 decode_path=decode_path,
4176 klass=self.__class__,
4177 decode_path=decode_path,
4181 l, llen, v = len_decode(lv)
4182 except DecodeError as err:
4183 raise err.__class__(
4185 klass=self.__class__,
4186 decode_path=decode_path,
4190 raise NotEnoughData(
4191 "encoded length is longer than data",
4192 klass=self.__class__,
4193 decode_path=decode_path,
4196 v, tail = v[:l], v[l:]
4197 sub_offset = offset + tlen + llen
4201 value, v_tail = spec.decode(
4205 decode_path=decode_path + (str(len(_value)),),
4206 defines_by_path=defines_by_path,
4208 sub_offset += (value.expl_tlvlen if value.expled else value.tlvlen)
4210 _value.append(value)
4211 obj = self.__class__(
4214 bounds=(self._bound_min, self._bound_max),
4217 default=self.default,
4218 optional=self.optional,
4219 _decoded=(offset, llen, l),
4225 pp_console_row(next(self.pps())),
4226 ", ".join(repr(v) for v in self._value),
4229 def pps(self, decode_path=()):
4231 asn1_type_name=self.asn1_type_name,
4232 obj_name=self.__class__.__name__,
4233 decode_path=decode_path,
4234 optional=self.optional,
4235 default=self == self.default,
4236 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4237 expl=None if self._expl is None else tag_decode(self._expl),
4242 expl_offset=self.expl_offset if self.expled else None,
4243 expl_tlen=self.expl_tlen if self.expled else None,
4244 expl_llen=self.expl_llen if self.expled else None,
4245 expl_vlen=self.expl_vlen if self.expled else None,
4247 for i, value in enumerate(self._value):
4248 yield value.pps(decode_path=decode_path + (str(i),))
4251 class SetOf(SequenceOf):
4252 """``SET OF`` sequence type
4254 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
4257 tag_default = tag_encode(form=TagFormConstructed, num=17)
4258 asn1_type_name = "SET OF"
4261 raws = self._encoded_values()
4264 return b"".join((self.tag, len_encode(len(v)), v))
4267 def obj_by_path(pypath): # pragma: no cover
4268 """Import object specified as string Python path
4270 Modules must be separated from classes/functions with ``:``.
4272 >>> obj_by_path("foo.bar:Baz")
4273 <class 'foo.bar.Baz'>
4274 >>> obj_by_path("foo.bar:Baz.boo")
4275 <classmethod 'foo.bar.Baz.boo'>
4277 mod, objs = pypath.rsplit(":", 1)
4278 from importlib import import_module
4279 obj = import_module(mod)
4280 for obj_name in objs.split("."):
4281 obj = getattr(obj, obj_name)
4285 def main(): # pragma: no cover
4287 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 DER decoder")
4288 parser.add_argument(
4290 help="Python path to dictionary with OIDs",
4292 parser.add_argument(
4294 help="Python path to schema definition to use",
4296 parser.add_argument(
4298 type=argparse.FileType("rb"),
4299 help="Path to DER file you want to decode",
4301 args = parser.parse_args()
4302 der = memoryview(args.DERFile.read())
4303 args.DERFile.close()
4304 oids = obj_by_path(args.oids) if args.oids else {}
4306 schema = obj_by_path(args.schema)
4307 from functools import partial
4308 pprinter = partial(pprint, big_blobs=True)
4310 # All of this below is a big hack with self references
4311 choice = PrimitiveTypes()
4312 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
4313 choice.specs["SetOf"] = SetOf(schema=choice)
4315 choice.specs["SequenceOf%d" % i] = SequenceOf(
4319 choice.specs["Any"] = Any()
4321 # Class name equals to type name, to omit it from output
4322 class SEQUENCEOF(SequenceOf):
4325 schema = SEQUENCEOF()
4327 def pprint_any(obj, oids=None):
4328 def _pprint_pps(pps):
4330 if hasattr(pp, "_fields"):
4331 if pp.asn1_type_name == Choice.asn1_type_name:
4333 pp_kwargs = pp._asdict()
4334 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
4335 pp = _pp(**pp_kwargs)
4336 yield pp_console_row(
4342 for row in pp_console_blob(pp):
4345 for row in _pprint_pps(pp):
4347 return "\n".join(_pprint_pps(obj.pps()))
4348 pprinter = pprint_any
4349 obj, tail = schema().decode(der)
4350 print(pprinter(obj, oids=oids))
4352 print("\nTrailing data: %s" % hexenc(tail))
4355 if __name__ == "__main__":