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 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:
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`` tells by which OID it
260 was defined, ``value`` contains corresponding decoded value. For example
261 above, ``content_info["content"].defined == (id_signedData,
264 .. _defines_by_path_kwarg:
266 defines_by_path kwarg
267 _____________________
269 Sometimes you either can not or do not want to explicitly set *defines*
270 in the scheme. You can dynamically apply those definitions when calling
271 ``.decode()`` method.
273 Decode method takes optional ``defines_by_path`` keyword argument that
274 must be sequence of following tuples::
276 (decode_path, defines)
278 where ``decode_path`` is a tuple holding so-called decode path to the
279 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
280 ``defines``, holding exactly the same value as accepted in its keyword
283 For example, again for CMS, you want to automatically decode
284 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
285 structures it may hold. Also, automatically decode ``controlSequence``
288 content_info, tail = ContentInfo().decode(data, defines_by_path=(
291 ("content", {id_signedData: SignedData()}),
296 decode_path_defby(id_signedData),
301 id_cct_PKIData: PKIData(),
302 id_cct_PKIResponse: PKIResponse(),
308 decode_path_defby(id_signedData),
311 decode_path_defby(id_cct_PKIResponse),
317 id_cmc_recipientNonce: RecipientNonce(),
318 id_cmc_senderNonce: SenderNonce(),
319 id_cmc_statusInfoV2: CMCStatusInfoV2(),
320 id_cmc_transactionId: TransactionId(),
325 Pay attention for :py:func:`pyderasn.decode_path_defby` and ``any``.
326 First function is useful for path construction when some automatic
327 decoding is already done. ``any`` means literally any value it meet --
328 useful for SEQUENCE/SET OF-s.
335 .. autoclass:: pyderasn.Boolean
340 .. autoclass:: pyderasn.Integer
345 .. autoclass:: pyderasn.BitString
350 .. autoclass:: pyderasn.OctetString
355 .. autoclass:: pyderasn.Null
360 .. autoclass:: pyderasn.ObjectIdentifier
365 .. autoclass:: pyderasn.Enumerated
369 .. autoclass:: pyderasn.CommonString
373 .. autoclass:: pyderasn.UTCTime
374 :members: __init__, todatetime
378 .. autoclass:: pyderasn.GeneralizedTime
385 .. autoclass:: pyderasn.Choice
390 .. autoclass:: PrimitiveTypes
394 .. autoclass:: pyderasn.Any
402 .. autoclass:: pyderasn.Sequence
407 .. autoclass:: pyderasn.Set
412 .. autoclass:: pyderasn.SequenceOf
417 .. autoclass:: pyderasn.SetOf
423 .. autofunction:: pyderasn.hexenc
424 .. autofunction:: pyderasn.hexdec
425 .. autofunction:: pyderasn.tag_encode
426 .. autofunction:: pyderasn.tag_decode
427 .. autofunction:: pyderasn.tag_ctxp
428 .. autofunction:: pyderasn.tag_ctxc
429 .. autoclass:: pyderasn.Obj
432 from codecs import getdecoder
433 from codecs import getencoder
434 from collections import namedtuple
435 from collections import OrderedDict
436 from datetime import datetime
437 from math import ceil
439 from six import add_metaclass
440 from six import binary_type
441 from six import byte2int
442 from six import indexbytes
443 from six import int2byte
444 from six import integer_types
445 from six import iterbytes
447 from six import string_types
448 from six import text_type
449 from six.moves import xrange as six_xrange
491 "TagClassApplication",
495 "TagFormConstructed",
506 TagClassUniversal = 0
507 TagClassApplication = 1 << 6
508 TagClassContext = 1 << 7
509 TagClassPrivate = 1 << 6 | 1 << 7
511 TagFormConstructed = 1 << 5
514 TagClassApplication: "APPLICATION ",
515 TagClassPrivate: "PRIVATE ",
516 TagClassUniversal: "UNIV ",
520 ########################################################################
522 ########################################################################
524 class DecodeError(Exception):
525 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
527 :param str msg: reason of decode failing
528 :param klass: optional exact DecodeError inherited class (like
529 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
530 :py:exc:`InvalidLength`)
531 :param decode_path: tuple of strings. It contains human
532 readable names of the fields through which
533 decoding process has passed
534 :param int offset: binary offset where failure happened
536 super(DecodeError, self).__init__()
539 self.decode_path = decode_path
545 "" if self.klass is None else self.klass.__name__,
547 ("(%s)" % ".".join(self.decode_path))
548 if len(self.decode_path) > 0 else ""
550 ("(at %d)" % self.offset) if self.offset > 0 else "",
556 return "%s(%s)" % (self.__class__.__name__, self)
559 class NotEnoughData(DecodeError):
563 class TagMismatch(DecodeError):
567 class InvalidLength(DecodeError):
571 class InvalidOID(DecodeError):
575 class ObjUnknown(ValueError):
576 def __init__(self, name):
577 super(ObjUnknown, self).__init__()
581 return "object is unknown: %s" % self.name
584 return "%s(%s)" % (self.__class__.__name__, self)
587 class ObjNotReady(ValueError):
588 def __init__(self, name):
589 super(ObjNotReady, self).__init__()
593 return "object is not ready: %s" % self.name
596 return "%s(%s)" % (self.__class__.__name__, self)
599 class InvalidValueType(ValueError):
600 def __init__(self, expected_types):
601 super(InvalidValueType, self).__init__()
602 self.expected_types = expected_types
605 return "invalid value type, expected: %s" % ", ".join(
606 [repr(t) for t in self.expected_types]
610 return "%s(%s)" % (self.__class__.__name__, self)
613 class BoundsError(ValueError):
614 def __init__(self, bound_min, value, bound_max):
615 super(BoundsError, self).__init__()
616 self.bound_min = bound_min
618 self.bound_max = bound_max
621 return "unsatisfied bounds: %s <= %s <= %s" % (
628 return "%s(%s)" % (self.__class__.__name__, self)
631 ########################################################################
633 ########################################################################
635 _hexdecoder = getdecoder("hex")
636 _hexencoder = getencoder("hex")
640 """Binary data to hexadecimal string convert
642 return _hexdecoder(data)[0]
646 """Hexadecimal string to binary data convert
648 return _hexencoder(data)[0].decode("ascii")
651 def int_bytes_len(num, byte_len=8):
654 return int(ceil(float(num.bit_length()) / byte_len))
657 def zero_ended_encode(num):
658 octets = bytearray(int_bytes_len(num, 7))
660 octets[i] = num & 0x7F
664 octets[i] = 0x80 | (num & 0x7F)
670 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
671 """Encode tag to binary form
673 :param int num: tag's number
674 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
675 :py:data:`pyderasn.TagClassContext`,
676 :py:data:`pyderasn.TagClassApplication`,
677 :py:data:`pyderasn.TagClassPrivate`)
678 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
679 :py:data:`pyderasn.TagFormConstructed`)
683 return int2byte(klass | form | num)
684 # [XX|X|11111][1.......][1.......] ... [0.......]
685 return int2byte(klass | form | 31) + zero_ended_encode(num)
689 """Decode tag from binary form
693 No validation is performed, assuming that it has already passed.
695 It returns tuple with three integers, as
696 :py:func:`pyderasn.tag_encode` accepts.
698 first_octet = byte2int(tag)
699 klass = first_octet & 0xC0
700 form = first_octet & 0x20
701 if first_octet & 0x1F < 0x1F:
702 return (klass, form, first_octet & 0x1F)
704 for octet in iterbytes(tag[1:]):
707 return (klass, form, num)
711 """Create CONTEXT PRIMITIVE tag
713 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
717 """Create CONTEXT CONSTRUCTED tag
719 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
723 """Take off tag from the data
725 :returns: (encoded tag, tag length, remaining data)
728 raise NotEnoughData("no data at all")
729 if byte2int(data) & 0x1F < 31:
730 return data[:1], 1, data[1:]
735 raise DecodeError("unfinished tag")
736 if indexbytes(data, i) & 0x80 == 0:
739 return data[:i], i, data[i:]
745 octets = bytearray(int_bytes_len(l) + 1)
746 octets[0] = 0x80 | (len(octets) - 1)
747 for i in six_xrange(len(octets) - 1, 0, -1):
753 def len_decode(data):
755 raise NotEnoughData("no data at all")
756 first_octet = byte2int(data)
757 if first_octet & 0x80 == 0:
758 return first_octet, 1, data[1:]
759 octets_num = first_octet & 0x7F
760 if octets_num + 1 > len(data):
761 raise NotEnoughData("encoded length is longer than data")
763 raise DecodeError("long form instead of short one")
764 if byte2int(data[1:]) == 0:
765 raise DecodeError("leading zeros")
767 for v in iterbytes(data[1:1 + octets_num]):
770 raise DecodeError("long form instead of short one")
771 return l, 1 + octets_num, data[1 + octets_num:]
774 ########################################################################
776 ########################################################################
778 class AutoAddSlots(type):
779 def __new__(cls, name, bases, _dict):
780 _dict["__slots__"] = _dict.get("__slots__", ())
781 return type.__new__(cls, name, bases, _dict)
784 @add_metaclass(AutoAddSlots)
786 """Common ASN.1 object class
788 All ASN.1 types are inherited from it. It has metaclass that
789 automatically adds ``__slots__`` to all inherited classes.
810 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
811 self._expl = getattr(self, "expl", None) if expl is None else expl
812 if self.tag != self.tag_default and self._expl is not None:
814 "implicit and explicit tags can not be set simultaneously"
816 if default is not None:
818 self.optional = optional
819 self.offset, self.llen, self.vlen = _decoded
823 def ready(self): # pragma: no cover
824 """Is object ready to be encoded?
826 raise NotImplementedError()
828 def _assert_ready(self):
830 raise ObjNotReady(self.__class__.__name__)
834 """Is object decoded?
836 return (self.llen + self.vlen) > 0
838 def copy(self): # pragma: no cover
839 """Make a copy of object, safe to be mutated
841 raise NotImplementedError()
849 return self.tlen + self.llen + self.vlen
851 def __str__(self): # pragma: no cover
852 return self.__bytes__() if PY2 else self.__unicode__()
854 def __ne__(self, their):
855 return not(self == their)
857 def __gt__(self, their): # pragma: no cover
858 return not(self < their)
860 def __le__(self, their): # pragma: no cover
861 return (self == their) or (self < their)
863 def __ge__(self, their): # pragma: no cover
864 return (self == their) or (self > their)
866 def _encode(self): # pragma: no cover
867 raise NotImplementedError()
869 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None): # pragma: no cover
870 raise NotImplementedError()
874 if self._expl is None:
876 return b"".join((self._expl, len_encode(len(raw)), raw))
878 def decode(self, data, offset=0, leavemm=False, decode_path=(), defines_by_path=None):
881 :param data: either binary or memoryview
882 :param int offset: initial data's offset
883 :param bool leavemm: do we need to leave memoryview of remaining
884 data as is, or convert it to bytes otherwise
885 :param defines_by_path: :ref:`Read about DEFINED BY <definedby>`
886 :returns: (Obj, remaining data)
888 tlv = memoryview(data)
889 if self._expl is None:
890 obj, tail = self._decode(
893 decode_path=decode_path,
894 defines_by_path=defines_by_path,
898 t, tlen, lv = tag_strip(tlv)
899 except DecodeError as err:
902 klass=self.__class__,
903 decode_path=decode_path,
908 klass=self.__class__,
909 decode_path=decode_path,
913 l, llen, v = len_decode(lv)
914 except DecodeError as err:
917 klass=self.__class__,
918 decode_path=decode_path,
923 "encoded length is longer than data",
924 klass=self.__class__,
925 decode_path=decode_path,
928 obj, tail = self._decode(
930 offset=offset + tlen + llen,
931 decode_path=decode_path,
932 defines_by_path=defines_by_path,
934 return obj, (tail if leavemm else tail.tobytes())
938 return self._expl is not None
946 return len(self._expl)
950 return len(len_encode(self.tlvlen))
953 def expl_offset(self):
954 return self.offset - self.expl_tlen - self.expl_llen
961 def expl_tlvlen(self):
962 return self.expl_tlen + self.expl_llen + self.expl_vlen
965 def decode_path_defby(defined_by):
966 """DEFINED BY representation inside decode path
968 return "DEFINED BY (%s)" % defined_by
971 ########################################################################
973 ########################################################################
975 PP = namedtuple("PP", (
997 asn1_type_name="unknown",
1036 def pp_console_row(pp, oids=None, with_offsets=False, with_blob=True):
1039 cols.append("%5d%s [%d,%d,%4d]" % (
1042 " " if pp.expl_offset is None else
1043 ("-%d" % (pp.offset - pp.expl_offset))
1049 if len(pp.decode_path) > 0:
1050 cols.append(" ." * (len(pp.decode_path)))
1051 cols.append("%s:" % pp.decode_path[-1])
1052 if pp.expl is not None:
1053 klass, _, num = pp.expl
1054 cols.append("[%s%d] EXPLICIT" % (TagClassReprs[klass], num))
1055 if pp.impl is not None:
1056 klass, _, num = pp.impl
1057 cols.append("[%s%d]" % (TagClassReprs[klass], num))
1058 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1059 cols.append(pp.obj_name)
1060 cols.append(pp.asn1_type_name)
1061 if pp.value is not None:
1064 oids is not None and
1065 pp.asn1_type_name == ObjectIdentifier.asn1_type_name and
1068 value = "%s (%s)" % (oids[value], pp.value)
1071 if isinstance(pp.blob, binary_type):
1072 cols.append(hexenc(pp.blob))
1073 elif isinstance(pp.blob, tuple):
1074 cols.append(", ".join(pp.blob))
1076 cols.append("OPTIONAL")
1078 cols.append("DEFAULT")
1079 return " ".join(cols)
1082 def pp_console_blob(pp):
1083 cols = [" " * len("XXXXXYY [X,X,XXXX]")]
1084 if len(pp.decode_path) > 0:
1085 cols.append(" ." * (len(pp.decode_path) + 1))
1086 if isinstance(pp.blob, binary_type):
1087 blob = hexenc(pp.blob).upper()
1088 for i in range(0, len(blob), 32):
1089 chunk = blob[i:i + 32]
1090 yield " ".join(cols + [":".join(
1091 chunk[j:j + 2] for j in range(0, len(chunk), 2)
1093 elif isinstance(pp.blob, tuple):
1094 yield " ".join(cols + [", ".join(pp.blob)])
1097 def pprint(obj, oids=None, big_blobs=False):
1098 """Pretty print object
1100 :param Obj obj: object you want to pretty print
1101 :param oids: ``OID <-> humand readable string`` dictionary. When OID
1102 from it is met, then its humand readable form is printed
1103 :param big_blobs: if large binary objects are met (like OctetString
1104 values), do we need to print them too, on separate
1107 def _pprint_pps(pps):
1109 if hasattr(pp, "_fields"):
1111 yield pp_console_row(
1117 for row in pp_console_blob(pp):
1120 yield pp_console_row(pp, oids=oids, with_offsets=True)
1122 for row in _pprint_pps(pp):
1124 return "\n".join(_pprint_pps(obj.pps()))
1127 ########################################################################
1128 # ASN.1 primitive types
1129 ########################################################################
1132 """``BOOLEAN`` boolean type
1134 >>> b = Boolean(True)
1136 >>> b == Boolean(True)
1142 tag_default = tag_encode(1)
1143 asn1_type_name = "BOOLEAN"
1155 :param value: set the value. Either boolean type, or
1156 :py:class:`pyderasn.Boolean` object
1157 :param bytes impl: override default tag with ``IMPLICIT`` one
1158 :param bytes expl: override default tag with ``EXPLICIT`` one
1159 :param default: set default value. Type same as in ``value``
1160 :param bool optional: is object ``OPTIONAL`` in sequence
1162 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1163 self._value = None if value is None else self._value_sanitize(value)
1164 if default is not None:
1165 default = self._value_sanitize(default)
1166 self.default = self.__class__(
1172 self._value = default
1174 def _value_sanitize(self, value):
1175 if issubclass(value.__class__, Boolean):
1177 if isinstance(value, bool):
1179 raise InvalidValueType((self.__class__, bool))
1183 return self._value is not None
1186 obj = self.__class__()
1187 obj._value = self._value
1189 obj._expl = self._expl
1190 obj.default = self.default
1191 obj.optional = self.optional
1192 obj.offset = self.offset
1193 obj.llen = self.llen
1194 obj.vlen = self.vlen
1197 def __nonzero__(self):
1198 self._assert_ready()
1202 self._assert_ready()
1205 def __eq__(self, their):
1206 if isinstance(their, bool):
1207 return self._value == their
1208 if not issubclass(their.__class__, Boolean):
1211 self._value == their._value and
1212 self.tag == their.tag and
1213 self._expl == their._expl
1224 return self.__class__(
1226 impl=self.tag if impl is None else impl,
1227 expl=self._expl if expl is None else expl,
1228 default=self.default if default is None else default,
1229 optional=self.optional if optional is None else optional,
1233 self._assert_ready()
1237 (b"\xFF" if self._value else b"\x00"),
1240 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
1242 t, _, lv = tag_strip(tlv)
1243 except DecodeError as err:
1244 raise err.__class__(
1246 klass=self.__class__,
1247 decode_path=decode_path,
1252 klass=self.__class__,
1253 decode_path=decode_path,
1257 l, _, v = len_decode(lv)
1258 except DecodeError as err:
1259 raise err.__class__(
1261 klass=self.__class__,
1262 decode_path=decode_path,
1266 raise InvalidLength(
1267 "Boolean's length must be equal to 1",
1268 klass=self.__class__,
1269 decode_path=decode_path,
1273 raise NotEnoughData(
1274 "encoded length is longer than data",
1275 klass=self.__class__,
1276 decode_path=decode_path,
1279 first_octet = byte2int(v)
1280 if first_octet == 0:
1282 elif first_octet == 0xFF:
1286 "unacceptable Boolean value",
1287 klass=self.__class__,
1288 decode_path=decode_path,
1291 obj = self.__class__(
1295 default=self.default,
1296 optional=self.optional,
1297 _decoded=(offset, 1, 1),
1302 return pp_console_row(next(self.pps()))
1304 def pps(self, decode_path=()):
1306 asn1_type_name=self.asn1_type_name,
1307 obj_name=self.__class__.__name__,
1308 decode_path=decode_path,
1309 value=str(self._value) if self.ready else None,
1310 optional=self.optional,
1311 default=self == self.default,
1312 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1313 expl=None if self._expl is None else tag_decode(self._expl),
1318 expl_offset=self.expl_offset if self.expled else None,
1319 expl_tlen=self.expl_tlen if self.expled else None,
1320 expl_llen=self.expl_llen if self.expled else None,
1321 expl_vlen=self.expl_vlen if self.expled else None,
1326 """``INTEGER`` integer type
1328 >>> b = Integer(-123)
1330 >>> b == Integer(-123)
1335 >>> Integer(2, bounds=(1, 3))
1337 >>> Integer(5, bounds=(1, 3))
1338 Traceback (most recent call last):
1339 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1343 class Version(Integer):
1350 >>> v = Version("v1")
1357 {'v3': 2, 'v1': 0, 'v2': 1}
1359 __slots__ = ("specs", "_bound_min", "_bound_max")
1360 tag_default = tag_encode(2)
1361 asn1_type_name = "INTEGER"
1375 :param value: set the value. Either integer type, named value
1376 (if ``schema`` is specified in the class), or
1377 :py:class:`pyderasn.Integer` object
1378 :param bounds: set ``(MIN, MAX)`` value constraint.
1379 (-inf, +inf) by default
1380 :param bytes impl: override default tag with ``IMPLICIT`` one
1381 :param bytes expl: override default tag with ``EXPLICIT`` one
1382 :param default: set default value. Type same as in ``value``
1383 :param bool optional: is object ``OPTIONAL`` in sequence
1385 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
1387 specs = getattr(self, "schema", {}) if _specs is None else _specs
1388 self.specs = specs if isinstance(specs, dict) else dict(specs)
1389 self._bound_min, self._bound_max = getattr(
1392 (float("-inf"), float("+inf")),
1393 ) if bounds is None else bounds
1394 if value is not None:
1395 self._value = self._value_sanitize(value)
1396 if default is not None:
1397 default = self._value_sanitize(default)
1398 self.default = self.__class__(
1404 if self._value is None:
1405 self._value = default
1407 def _value_sanitize(self, value):
1408 if issubclass(value.__class__, Integer):
1409 value = value._value
1410 elif isinstance(value, integer_types):
1412 elif isinstance(value, str):
1413 value = self.specs.get(value)
1415 raise ObjUnknown("integer value: %s" % value)
1417 raise InvalidValueType((self.__class__, int, str))
1418 if not self._bound_min <= value <= self._bound_max:
1419 raise BoundsError(self._bound_min, value, self._bound_max)
1424 return self._value is not None
1427 obj = self.__class__(_specs=self.specs)
1428 obj._value = self._value
1429 obj._bound_min = self._bound_min
1430 obj._bound_max = self._bound_max
1432 obj._expl = self._expl
1433 obj.default = self.default
1434 obj.optional = self.optional
1435 obj.offset = self.offset
1436 obj.llen = self.llen
1437 obj.vlen = self.vlen
1441 self._assert_ready()
1442 return int(self._value)
1445 self._assert_ready()
1448 bytes(self._expl or b"") +
1449 str(self._value).encode("ascii"),
1452 def __eq__(self, their):
1453 if isinstance(their, integer_types):
1454 return self._value == their
1455 if not issubclass(their.__class__, Integer):
1458 self._value == their._value and
1459 self.tag == their.tag and
1460 self._expl == their._expl
1463 def __lt__(self, their):
1464 return self._value < their._value
1468 for name, value in self.specs.items():
1469 if value == self._value:
1481 return self.__class__(
1484 (self._bound_min, self._bound_max)
1485 if bounds is None else bounds
1487 impl=self.tag if impl is None else impl,
1488 expl=self._expl if expl is None else expl,
1489 default=self.default if default is None else default,
1490 optional=self.optional if optional is None else optional,
1495 self._assert_ready()
1499 octets = bytearray([0])
1503 octets = bytearray()
1505 octets.append((value & 0xFF) ^ 0xFF)
1507 if len(octets) == 0 or octets[-1] & 0x80 == 0:
1510 octets = bytearray()
1512 octets.append(value & 0xFF)
1514 if octets[-1] & 0x80 > 0:
1517 octets = bytes(octets)
1519 bytes_len = ceil(value.bit_length() / 8) or 1
1522 octets = value.to_bytes(
1527 except OverflowError:
1531 return b"".join((self.tag, len_encode(len(octets)), octets))
1533 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
1535 t, _, lv = tag_strip(tlv)
1536 except DecodeError as err:
1537 raise err.__class__(
1539 klass=self.__class__,
1540 decode_path=decode_path,
1545 klass=self.__class__,
1546 decode_path=decode_path,
1550 l, llen, v = len_decode(lv)
1551 except DecodeError as err:
1552 raise err.__class__(
1554 klass=self.__class__,
1555 decode_path=decode_path,
1559 raise NotEnoughData(
1560 "encoded length is longer than data",
1561 klass=self.__class__,
1562 decode_path=decode_path,
1566 raise NotEnoughData(
1568 klass=self.__class__,
1569 decode_path=decode_path,
1572 v, tail = v[:l], v[l:]
1573 first_octet = byte2int(v)
1575 second_octet = byte2int(v[1:])
1577 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
1578 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
1581 "non normalized integer",
1582 klass=self.__class__,
1583 decode_path=decode_path,
1588 if first_octet & 0x80 > 0:
1589 octets = bytearray()
1590 for octet in bytearray(v):
1591 octets.append(octet ^ 0xFF)
1592 for octet in octets:
1593 value = (value << 8) | octet
1597 for octet in bytearray(v):
1598 value = (value << 8) | octet
1600 value = int.from_bytes(v, byteorder="big", signed=True)
1602 obj = self.__class__(
1604 bounds=(self._bound_min, self._bound_max),
1607 default=self.default,
1608 optional=self.optional,
1610 _decoded=(offset, llen, l),
1612 except BoundsError as err:
1615 klass=self.__class__,
1616 decode_path=decode_path,
1622 return pp_console_row(next(self.pps()))
1624 def pps(self, decode_path=()):
1626 asn1_type_name=self.asn1_type_name,
1627 obj_name=self.__class__.__name__,
1628 decode_path=decode_path,
1629 value=(self.named or str(self._value)) if self.ready else None,
1630 optional=self.optional,
1631 default=self == self.default,
1632 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1633 expl=None if self._expl is None else tag_decode(self._expl),
1638 expl_offset=self.expl_offset if self.expled else None,
1639 expl_tlen=self.expl_tlen if self.expled else None,
1640 expl_llen=self.expl_llen if self.expled else None,
1641 expl_vlen=self.expl_vlen if self.expled else None,
1645 class BitString(Obj):
1646 """``BIT STRING`` bit string type
1648 >>> BitString(b"hello world")
1649 BIT STRING 88 bits 68656c6c6f20776f726c64
1652 >>> b == b"hello world"
1657 >>> b = BitString("'010110000000'B")
1658 BIT STRING 12 bits 5800
1661 >>> b[0], b[1], b[2], b[3]
1662 (False, True, False, True)
1666 [False, True, False, True, True, False, False, False, False, False, False, False]
1670 class KeyUsage(BitString):
1672 ('digitalSignature', 0),
1673 ('nonRepudiation', 1),
1674 ('keyEncipherment', 2),
1677 >>> b = KeyUsage(('keyEncipherment', 'nonRepudiation'))
1678 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
1680 ['nonRepudiation', 'keyEncipherment']
1682 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
1684 __slots__ = ("specs",)
1685 tag_default = tag_encode(3)
1686 asn1_type_name = "BIT STRING"
1699 :param value: set the value. Either binary type, tuple of named
1700 values (if ``schema`` is specified in the class),
1701 string in ``'XXX...'B`` form, or
1702 :py:class:`pyderasn.BitString` object
1703 :param bytes impl: override default tag with ``IMPLICIT`` one
1704 :param bytes expl: override default tag with ``EXPLICIT`` one
1705 :param default: set default value. Type same as in ``value``
1706 :param bool optional: is object ``OPTIONAL`` in sequence
1708 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
1709 specs = getattr(self, "schema", {}) if _specs is None else _specs
1710 self.specs = specs if isinstance(specs, dict) else dict(specs)
1711 self._value = None if value is None else self._value_sanitize(value)
1712 if default is not None:
1713 default = self._value_sanitize(default)
1714 self.default = self.__class__(
1720 self._value = default
1722 def _bits2octets(self, bits):
1723 if len(self.specs) > 0:
1724 bits = bits.rstrip("0")
1726 bits += "0" * ((8 - (bit_len % 8)) % 8)
1727 octets = bytearray(len(bits) // 8)
1728 for i in six_xrange(len(octets)):
1729 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
1730 return bit_len, bytes(octets)
1732 def _value_sanitize(self, value):
1733 if issubclass(value.__class__, BitString):
1735 if isinstance(value, (string_types, binary_type)):
1737 isinstance(value, string_types) and
1738 value.startswith("'") and
1739 value.endswith("'B")
1742 if not set(value) <= set(("0", "1")):
1743 raise ValueError("B's coding contains unacceptable chars")
1744 return self._bits2octets(value)
1745 elif isinstance(value, binary_type):
1746 return (len(value) * 8, value)
1748 raise InvalidValueType((
1753 if isinstance(value, tuple):
1756 isinstance(value[0], integer_types) and
1757 isinstance(value[1], binary_type)
1762 bit = self.specs.get(name)
1764 raise ObjUnknown("BitString value: %s" % name)
1767 return self._bits2octets("")
1769 return self._bits2octets("".join(
1770 ("1" if bit in bits else "0")
1771 for bit in six_xrange(max(bits) + 1)
1773 raise InvalidValueType((self.__class__, binary_type, string_types))
1777 return self._value is not None
1780 obj = self.__class__(_specs=self.specs)
1782 if value is not None:
1783 value = (value[0], value[1])
1786 obj._expl = self._expl
1787 obj.default = self.default
1788 obj.optional = self.optional
1789 obj.offset = self.offset
1790 obj.llen = self.llen
1791 obj.vlen = self.vlen
1795 self._assert_ready()
1796 for i in six_xrange(self._value[0]):
1801 self._assert_ready()
1802 return self._value[0]
1804 def __bytes__(self):
1805 self._assert_ready()
1806 return self._value[1]
1808 def __eq__(self, their):
1809 if isinstance(their, bytes):
1810 return self._value[1] == their
1811 if not issubclass(their.__class__, BitString):
1814 self._value == their._value and
1815 self.tag == their.tag and
1816 self._expl == their._expl
1821 return [name for name, bit in self.specs.items() if self[bit]]
1831 return self.__class__(
1833 impl=self.tag if impl is None else impl,
1834 expl=self._expl if expl is None else expl,
1835 default=self.default if default is None else default,
1836 optional=self.optional if optional is None else optional,
1840 def __getitem__(self, key):
1841 if isinstance(key, int):
1842 bit_len, octets = self._value
1846 byte2int(memoryview(octets)[key // 8:]) >>
1849 if isinstance(key, string_types):
1850 value = self.specs.get(key)
1852 raise ObjUnknown("BitString value: %s" % key)
1854 raise InvalidValueType((int, str))
1857 self._assert_ready()
1858 bit_len, octets = self._value
1861 len_encode(len(octets) + 1),
1862 int2byte((8 - bit_len % 8) % 8),
1866 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
1868 t, _, lv = tag_strip(tlv)
1869 except DecodeError as err:
1870 raise err.__class__(
1872 klass=self.__class__,
1873 decode_path=decode_path,
1878 klass=self.__class__,
1879 decode_path=decode_path,
1883 l, llen, v = len_decode(lv)
1884 except DecodeError as err:
1885 raise err.__class__(
1887 klass=self.__class__,
1888 decode_path=decode_path,
1892 raise NotEnoughData(
1893 "encoded length is longer than data",
1894 klass=self.__class__,
1895 decode_path=decode_path,
1899 raise NotEnoughData(
1901 klass=self.__class__,
1902 decode_path=decode_path,
1905 pad_size = byte2int(v)
1906 if l == 1 and pad_size != 0:
1908 "invalid empty value",
1909 klass=self.__class__,
1910 decode_path=decode_path,
1916 klass=self.__class__,
1917 decode_path=decode_path,
1920 if byte2int(v[-1:]) & ((1 << pad_size) - 1) != 0:
1923 klass=self.__class__,
1924 decode_path=decode_path,
1927 v, tail = v[:l], v[l:]
1928 obj = self.__class__(
1929 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
1932 default=self.default,
1933 optional=self.optional,
1935 _decoded=(offset, llen, l),
1940 return pp_console_row(next(self.pps()))
1942 def pps(self, decode_path=()):
1946 bit_len, blob = self._value
1947 value = "%d bits" % bit_len
1948 if len(self.specs) > 0:
1949 blob = tuple(self.named)
1951 asn1_type_name=self.asn1_type_name,
1952 obj_name=self.__class__.__name__,
1953 decode_path=decode_path,
1956 optional=self.optional,
1957 default=self == self.default,
1958 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1959 expl=None if self._expl is None else tag_decode(self._expl),
1964 expl_offset=self.expl_offset if self.expled else None,
1965 expl_tlen=self.expl_tlen if self.expled else None,
1966 expl_llen=self.expl_llen if self.expled else None,
1967 expl_vlen=self.expl_vlen if self.expled else None,
1971 class OctetString(Obj):
1972 """``OCTET STRING`` binary string type
1974 >>> s = OctetString(b"hello world")
1975 OCTET STRING 11 bytes 68656c6c6f20776f726c64
1976 >>> s == OctetString(b"hello world")
1981 >>> OctetString(b"hello", bounds=(4, 4))
1982 Traceback (most recent call last):
1983 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
1984 >>> OctetString(b"hell", bounds=(4, 4))
1985 OCTET STRING 4 bytes 68656c6c
1987 __slots__ = ("_bound_min", "_bound_max", "defined")
1988 tag_default = tag_encode(4)
1989 asn1_type_name = "OCTET STRING"
2002 :param value: set the value. Either binary type, or
2003 :py:class:`pyderasn.OctetString` object
2004 :param bounds: set ``(MIN, MAX)`` value size constraint.
2005 (-inf, +inf) by default
2006 :param bytes impl: override default tag with ``IMPLICIT`` one
2007 :param bytes expl: override default tag with ``EXPLICIT`` one
2008 :param default: set default value. Type same as in ``value``
2009 :param bool optional: is object ``OPTIONAL`` in sequence
2011 super(OctetString, self).__init__(
2019 self._bound_min, self._bound_max = getattr(
2023 ) if bounds is None else bounds
2024 if value is not None:
2025 self._value = self._value_sanitize(value)
2026 if default is not None:
2027 default = self._value_sanitize(default)
2028 self.default = self.__class__(
2033 if self._value is None:
2034 self._value = default
2037 def _value_sanitize(self, value):
2038 if issubclass(value.__class__, OctetString):
2039 value = value._value
2040 elif isinstance(value, binary_type):
2043 raise InvalidValueType((self.__class__, bytes))
2044 if not self._bound_min <= len(value) <= self._bound_max:
2045 raise BoundsError(self._bound_min, len(value), self._bound_max)
2050 return self._value is not None
2053 obj = self.__class__()
2054 obj._value = self._value
2055 obj._bound_min = self._bound_min
2056 obj._bound_max = self._bound_max
2058 obj._expl = self._expl
2059 obj.default = self.default
2060 obj.optional = self.optional
2061 obj.offset = self.offset
2062 obj.llen = self.llen
2063 obj.vlen = self.vlen
2066 def __bytes__(self):
2067 self._assert_ready()
2070 def __eq__(self, their):
2071 if isinstance(their, binary_type):
2072 return self._value == their
2073 if not issubclass(their.__class__, OctetString):
2076 self._value == their._value and
2077 self.tag == their.tag and
2078 self._expl == their._expl
2081 def __lt__(self, their):
2082 return self._value < their._value
2093 return self.__class__(
2096 (self._bound_min, self._bound_max)
2097 if bounds is None else bounds
2099 impl=self.tag if impl is None else impl,
2100 expl=self._expl if expl is None else expl,
2101 default=self.default if default is None else default,
2102 optional=self.optional if optional is None else optional,
2106 self._assert_ready()
2109 len_encode(len(self._value)),
2113 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
2115 t, _, lv = tag_strip(tlv)
2116 except DecodeError as err:
2117 raise err.__class__(
2119 klass=self.__class__,
2120 decode_path=decode_path,
2125 klass=self.__class__,
2126 decode_path=decode_path,
2130 l, llen, v = len_decode(lv)
2131 except DecodeError as err:
2132 raise err.__class__(
2134 klass=self.__class__,
2135 decode_path=decode_path,
2139 raise NotEnoughData(
2140 "encoded length is longer than data",
2141 klass=self.__class__,
2142 decode_path=decode_path,
2145 v, tail = v[:l], v[l:]
2147 obj = self.__class__(
2149 bounds=(self._bound_min, self._bound_max),
2152 default=self.default,
2153 optional=self.optional,
2154 _decoded=(offset, llen, l),
2156 except BoundsError as err:
2159 klass=self.__class__,
2160 decode_path=decode_path,
2166 return pp_console_row(next(self.pps()))
2168 def pps(self, decode_path=()):
2170 asn1_type_name=self.asn1_type_name,
2171 obj_name=self.__class__.__name__,
2172 decode_path=decode_path,
2173 value=("%d bytes" % len(self._value)) if self.ready else None,
2174 blob=self._value if self.ready else None,
2175 optional=self.optional,
2176 default=self == self.default,
2177 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2178 expl=None if self._expl is None else tag_decode(self._expl),
2183 expl_offset=self.expl_offset if self.expled else None,
2184 expl_tlen=self.expl_tlen if self.expled else None,
2185 expl_llen=self.expl_llen if self.expled else None,
2186 expl_vlen=self.expl_vlen if self.expled else None,
2188 defined_by, defined = self.defined or (None, None)
2189 if defined_by is not None:
2191 decode_path=decode_path + (decode_path_defby(defined_by),)
2196 """``NULL`` null object
2204 tag_default = tag_encode(5)
2205 asn1_type_name = "NULL"
2209 value=None, # unused, but Sequence passes it
2216 :param bytes impl: override default tag with ``IMPLICIT`` one
2217 :param bytes expl: override default tag with ``EXPLICIT`` one
2218 :param bool optional: is object ``OPTIONAL`` in sequence
2220 super(Null, self).__init__(impl, expl, None, optional, _decoded)
2228 obj = self.__class__()
2230 obj._expl = self._expl
2231 obj.default = self.default
2232 obj.optional = self.optional
2233 obj.offset = self.offset
2234 obj.llen = self.llen
2235 obj.vlen = self.vlen
2238 def __eq__(self, their):
2239 if not issubclass(their.__class__, Null):
2242 self.tag == their.tag and
2243 self._expl == their._expl
2253 return self.__class__(
2254 impl=self.tag if impl is None else impl,
2255 expl=self._expl if expl is None else expl,
2256 optional=self.optional if optional is None else optional,
2260 return self.tag + len_encode(0)
2262 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
2264 t, _, lv = tag_strip(tlv)
2265 except DecodeError as err:
2266 raise err.__class__(
2268 klass=self.__class__,
2269 decode_path=decode_path,
2274 klass=self.__class__,
2275 decode_path=decode_path,
2279 l, _, v = len_decode(lv)
2280 except DecodeError as err:
2281 raise err.__class__(
2283 klass=self.__class__,
2284 decode_path=decode_path,
2288 raise InvalidLength(
2289 "Null must have zero length",
2290 klass=self.__class__,
2291 decode_path=decode_path,
2294 obj = self.__class__(
2297 optional=self.optional,
2298 _decoded=(offset, 1, 0),
2303 return pp_console_row(next(self.pps()))
2305 def pps(self, decode_path=()):
2307 asn1_type_name=self.asn1_type_name,
2308 obj_name=self.__class__.__name__,
2309 decode_path=decode_path,
2310 optional=self.optional,
2311 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2312 expl=None if self._expl is None else tag_decode(self._expl),
2317 expl_offset=self.expl_offset if self.expled else None,
2318 expl_tlen=self.expl_tlen if self.expled else None,
2319 expl_llen=self.expl_llen if self.expled else None,
2320 expl_vlen=self.expl_vlen if self.expled else None,
2324 class ObjectIdentifier(Obj):
2325 """``OBJECT IDENTIFIER`` OID type
2327 >>> oid = ObjectIdentifier((1, 2, 3))
2328 OBJECT IDENTIFIER 1.2.3
2329 >>> oid == ObjectIdentifier("1.2.3")
2335 >>> oid + (4, 5) + ObjectIdentifier("1.7")
2336 OBJECT IDENTIFIER 1.2.3.4.5.1.7
2338 >>> str(ObjectIdentifier((3, 1)))
2339 Traceback (most recent call last):
2340 pyderasn.InvalidOID: unacceptable first arc value
2342 __slots__ = ("defines",)
2343 tag_default = tag_encode(6)
2344 asn1_type_name = "OBJECT IDENTIFIER"
2357 :param value: set the value. Either tuples of integers,
2358 string of "."-concatenated integers, or
2359 :py:class:`pyderasn.ObjectIdentifier` object
2360 :param defines: tuple of two elements. First one is a name of
2361 field inside :py:class:`pyderasn.Sequence`,
2362 defining with that OID. Second element is a
2363 ``{OID: pyderasn.Obj()}`` dictionary, mapping
2364 between current OID value and structure applied
2366 :ref:`Read about DEFINED BY <definedby>`
2367 :param bytes impl: override default tag with ``IMPLICIT`` one
2368 :param bytes expl: override default tag with ``EXPLICIT`` one
2369 :param default: set default value. Type same as in ``value``
2370 :param bool optional: is object ``OPTIONAL`` in sequence
2372 super(ObjectIdentifier, self).__init__(
2380 if value is not None:
2381 self._value = self._value_sanitize(value)
2382 if default is not None:
2383 default = self._value_sanitize(default)
2384 self.default = self.__class__(
2389 if self._value is None:
2390 self._value = default
2391 self.defines = defines
2393 def __add__(self, their):
2394 if isinstance(their, self.__class__):
2395 return self.__class__(self._value + their._value)
2396 if isinstance(their, tuple):
2397 return self.__class__(self._value + their)
2398 raise InvalidValueType((self.__class__, tuple))
2400 def _value_sanitize(self, value):
2401 if issubclass(value.__class__, ObjectIdentifier):
2403 if isinstance(value, string_types):
2405 value = tuple(int(arc) for arc in value.split("."))
2407 raise InvalidOID("unacceptable arcs values")
2408 if isinstance(value, tuple):
2410 raise InvalidOID("less than 2 arcs")
2411 first_arc = value[0]
2412 if first_arc in (0, 1):
2413 if not (0 <= value[1] <= 39):
2414 raise InvalidOID("second arc is too wide")
2415 elif first_arc == 2:
2418 raise InvalidOID("unacceptable first arc value")
2420 raise InvalidValueType((self.__class__, str, tuple))
2424 return self._value is not None
2427 obj = self.__class__()
2428 obj._value = self._value
2429 obj.defines = self.defines
2431 obj._expl = self._expl
2432 obj.default = self.default
2433 obj.optional = self.optional
2434 obj.offset = self.offset
2435 obj.llen = self.llen
2436 obj.vlen = self.vlen
2440 self._assert_ready()
2441 return iter(self._value)
2444 return ".".join(str(arc) for arc in self._value or ())
2447 self._assert_ready()
2450 bytes(self._expl or b"") +
2451 str(self._value).encode("ascii"),
2454 def __eq__(self, their):
2455 if isinstance(their, tuple):
2456 return self._value == their
2457 if not issubclass(their.__class__, ObjectIdentifier):
2460 self.tag == their.tag and
2461 self._expl == their._expl and
2462 self._value == their._value
2465 def __lt__(self, their):
2466 return self._value < their._value
2477 return self.__class__(
2479 defines=self.defines if defines is None else defines,
2480 impl=self.tag if impl is None else impl,
2481 expl=self._expl if expl is None else expl,
2482 default=self.default if default is None else default,
2483 optional=self.optional if optional is None else optional,
2487 self._assert_ready()
2489 first_value = value[1]
2490 first_arc = value[0]
2493 elif first_arc == 1:
2495 elif first_arc == 2:
2497 else: # pragma: no cover
2498 raise RuntimeError("invalid arc is stored")
2499 octets = [zero_ended_encode(first_value)]
2500 for arc in value[2:]:
2501 octets.append(zero_ended_encode(arc))
2502 v = b"".join(octets)
2503 return b"".join((self.tag, len_encode(len(v)), v))
2505 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
2507 t, _, lv = tag_strip(tlv)
2508 except DecodeError as err:
2509 raise err.__class__(
2511 klass=self.__class__,
2512 decode_path=decode_path,
2517 klass=self.__class__,
2518 decode_path=decode_path,
2522 l, llen, v = len_decode(lv)
2523 except DecodeError as err:
2524 raise err.__class__(
2526 klass=self.__class__,
2527 decode_path=decode_path,
2531 raise NotEnoughData(
2532 "encoded length is longer than data",
2533 klass=self.__class__,
2534 decode_path=decode_path,
2538 raise NotEnoughData(
2540 klass=self.__class__,
2541 decode_path=decode_path,
2544 v, tail = v[:l], v[l:]
2550 octet = indexbytes(v, i)
2551 arc = (arc << 7) | (octet & 0x7F)
2552 if octet & 0x80 == 0:
2560 klass=self.__class__,
2561 decode_path=decode_path,
2565 second_arc = arcs[0]
2566 if 0 <= second_arc <= 39:
2568 elif 40 <= second_arc <= 79:
2574 obj = self.__class__(
2575 value=tuple([first_arc, second_arc] + arcs[1:]),
2578 default=self.default,
2579 optional=self.optional,
2580 _decoded=(offset, llen, l),
2585 return pp_console_row(next(self.pps()))
2587 def pps(self, decode_path=()):
2589 asn1_type_name=self.asn1_type_name,
2590 obj_name=self.__class__.__name__,
2591 decode_path=decode_path,
2592 value=str(self) if self.ready else None,
2593 optional=self.optional,
2594 default=self == self.default,
2595 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2596 expl=None if self._expl is None else tag_decode(self._expl),
2601 expl_offset=self.expl_offset if self.expled else None,
2602 expl_tlen=self.expl_tlen if self.expled else None,
2603 expl_llen=self.expl_llen if self.expled else None,
2604 expl_vlen=self.expl_vlen if self.expled else None,
2608 class Enumerated(Integer):
2609 """``ENUMERATED`` integer type
2611 This type is identical to :py:class:`pyderasn.Integer`, but requires
2612 schema to be specified and does not accept values missing from it.
2615 tag_default = tag_encode(10)
2616 asn1_type_name = "ENUMERATED"
2627 bounds=None, # dummy argument, workability for Integer.decode
2629 super(Enumerated, self).__init__(
2638 if len(self.specs) == 0:
2639 raise ValueError("schema must be specified")
2641 def _value_sanitize(self, value):
2642 if isinstance(value, self.__class__):
2643 value = value._value
2644 elif isinstance(value, integer_types):
2645 if value not in list(self.specs.values()):
2647 "unknown integer value: %s" % value,
2648 klass=self.__class__,
2650 elif isinstance(value, string_types):
2651 value = self.specs.get(value)
2653 raise ObjUnknown("integer value: %s" % value)
2655 raise InvalidValueType((self.__class__, int, str))
2659 obj = self.__class__(_specs=self.specs)
2660 obj._value = self._value
2661 obj._bound_min = self._bound_min
2662 obj._bound_max = self._bound_max
2664 obj._expl = self._expl
2665 obj.default = self.default
2666 obj.optional = self.optional
2667 obj.offset = self.offset
2668 obj.llen = self.llen
2669 obj.vlen = self.vlen
2681 return self.__class__(
2683 impl=self.tag if impl is None else impl,
2684 expl=self._expl if expl is None else expl,
2685 default=self.default if default is None else default,
2686 optional=self.optional if optional is None else optional,
2691 class CommonString(OctetString):
2692 """Common class for all strings
2694 Everything resembles :py:class:`pyderasn.OctetString`, except
2695 ability to deal with unicode text strings.
2697 >>> hexenc("привет мир".encode("utf-8"))
2698 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
2699 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
2701 >>> s = UTF8String("привет мир")
2702 UTF8String UTF8String привет мир
2704 'привет мир'
2705 >>> hexenc(bytes(s))
2706 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
2708 >>> PrintableString("привет мир")
2709 Traceback (most recent call last):
2710 UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
2712 >>> BMPString("ада", bounds=(2, 2))
2713 Traceback (most recent call last):
2714 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
2715 >>> s = BMPString("ад", bounds=(2, 2))
2718 >>> hexenc(bytes(s))
2726 * - :py:class:`pyderasn.UTF8String`
2728 * - :py:class:`pyderasn.NumericString`
2730 * - :py:class:`pyderasn.PrintableString`
2732 * - :py:class:`pyderasn.TeletexString`
2734 * - :py:class:`pyderasn.T61String`
2736 * - :py:class:`pyderasn.VideotexString`
2738 * - :py:class:`pyderasn.IA5String`
2740 * - :py:class:`pyderasn.GraphicString`
2742 * - :py:class:`pyderasn.VisibleString`
2744 * - :py:class:`pyderasn.ISO646String`
2746 * - :py:class:`pyderasn.GeneralString`
2748 * - :py:class:`pyderasn.UniversalString`
2750 * - :py:class:`pyderasn.BMPString`
2753 __slots__ = ("encoding",)
2755 def _value_sanitize(self, value):
2757 value_decoded = None
2758 if isinstance(value, self.__class__):
2759 value_raw = value._value
2760 elif isinstance(value, text_type):
2761 value_decoded = value
2762 elif isinstance(value, binary_type):
2765 raise InvalidValueType((self.__class__, text_type, binary_type))
2767 value_decoded.encode(self.encoding)
2768 if value_raw is None else value_raw
2771 value_raw.decode(self.encoding)
2772 if value_decoded is None else value_decoded
2774 if not self._bound_min <= len(value_decoded) <= self._bound_max:
2782 def __eq__(self, their):
2783 if isinstance(their, binary_type):
2784 return self._value == their
2785 if isinstance(their, text_type):
2786 return self._value == their.encode(self.encoding)
2787 if not isinstance(their, self.__class__):
2790 self._value == their._value and
2791 self.tag == their.tag and
2792 self._expl == their._expl
2795 def __unicode__(self):
2797 return self._value.decode(self.encoding)
2798 return text_type(self._value)
2801 return pp_console_row(next(self.pps(no_unicode=PY2)))
2803 def pps(self, decode_path=(), no_unicode=False):
2806 value = hexenc(bytes(self)) if no_unicode else self.__unicode__()
2808 asn1_type_name=self.asn1_type_name,
2809 obj_name=self.__class__.__name__,
2810 decode_path=decode_path,
2812 optional=self.optional,
2813 default=self == self.default,
2814 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2815 expl=None if self._expl is None else tag_decode(self._expl),
2823 class UTF8String(CommonString):
2825 tag_default = tag_encode(12)
2827 asn1_type_name = "UTF8String"
2830 class NumericString(CommonString):
2832 tag_default = tag_encode(18)
2834 asn1_type_name = "NumericString"
2837 class PrintableString(CommonString):
2839 tag_default = tag_encode(19)
2841 asn1_type_name = "PrintableString"
2844 class TeletexString(CommonString):
2846 tag_default = tag_encode(20)
2848 asn1_type_name = "TeletexString"
2851 class T61String(TeletexString):
2853 asn1_type_name = "T61String"
2856 class VideotexString(CommonString):
2858 tag_default = tag_encode(21)
2859 encoding = "iso-8859-1"
2860 asn1_type_name = "VideotexString"
2863 class IA5String(CommonString):
2865 tag_default = tag_encode(22)
2867 asn1_type_name = "IA5"
2870 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
2871 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
2872 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
2875 class UTCTime(CommonString):
2876 """``UTCTime`` datetime type
2878 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
2879 UTCTime UTCTime 2017-09-30T22:07:50
2885 datetime.datetime(2017, 9, 30, 22, 7, 50)
2886 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
2887 datetime.datetime(1957, 9, 30, 22, 7, 50)
2890 tag_default = tag_encode(23)
2892 asn1_type_name = "UTCTime"
2894 fmt = "%y%m%d%H%M%SZ"
2904 bounds=None, # dummy argument, workability for OctetString.decode
2907 :param value: set the value. Either datetime type, or
2908 :py:class:`pyderasn.UTCTime` object
2909 :param bytes impl: override default tag with ``IMPLICIT`` one
2910 :param bytes expl: override default tag with ``EXPLICIT`` one
2911 :param default: set default value. Type same as in ``value``
2912 :param bool optional: is object ``OPTIONAL`` in sequence
2914 super(UTCTime, self).__init__(
2922 if value is not None:
2923 self._value = self._value_sanitize(value)
2924 if default is not None:
2925 default = self._value_sanitize(default)
2926 self.default = self.__class__(
2931 if self._value is None:
2932 self._value = default
2934 def _value_sanitize(self, value):
2935 if isinstance(value, self.__class__):
2937 if isinstance(value, datetime):
2938 return value.strftime(self.fmt).encode("ascii")
2939 if isinstance(value, binary_type):
2940 value_decoded = value.decode("ascii")
2941 if len(value_decoded) == LEN_YYMMDDHHMMSSZ:
2943 datetime.strptime(value_decoded, self.fmt)
2945 raise DecodeError("invalid UTCTime format")
2948 raise DecodeError("invalid UTCTime length")
2949 raise InvalidValueType((self.__class__, datetime))
2951 def __eq__(self, their):
2952 if isinstance(their, binary_type):
2953 return self._value == their
2954 if isinstance(their, datetime):
2955 return self.todatetime() == their
2956 if not isinstance(their, self.__class__):
2959 self._value == their._value and
2960 self.tag == their.tag and
2961 self._expl == their._expl
2964 def todatetime(self):
2965 """Convert to datetime
2969 Pay attention that UTCTime can not hold full year, so all years
2970 having < 50 years are treated as 20xx, 19xx otherwise, according
2971 to X.509 recomendation.
2973 value = datetime.strptime(self._value.decode("ascii"), self.fmt)
2974 year = value.year % 100
2976 year=(2000 + year) if year < 50 else (1900 + year),
2980 minute=value.minute,
2981 second=value.second,
2985 return pp_console_row(next(self.pps()))
2987 def pps(self, decode_path=()):
2989 asn1_type_name=self.asn1_type_name,
2990 obj_name=self.__class__.__name__,
2991 decode_path=decode_path,
2992 value=self.todatetime().isoformat() if self.ready else None,
2993 optional=self.optional,
2994 default=self == self.default,
2995 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2996 expl=None if self._expl is None else tag_decode(self._expl),
3004 class GeneralizedTime(UTCTime):
3005 """``GeneralizedTime`` datetime type
3007 This type is similar to :py:class:`pyderasn.UTCTime`.
3009 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3010 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
3012 '20170930220750.000123Z'
3013 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
3014 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
3017 tag_default = tag_encode(24)
3018 asn1_type_name = "GeneralizedTime"
3020 fmt = "%Y%m%d%H%M%SZ"
3021 fmt_ms = "%Y%m%d%H%M%S.%fZ"
3023 def _value_sanitize(self, value):
3024 if isinstance(value, self.__class__):
3026 if isinstance(value, datetime):
3027 return value.strftime(
3028 self.fmt_ms if value.microsecond > 0 else self.fmt
3030 if isinstance(value, binary_type):
3031 value_decoded = value.decode("ascii")
3032 if len(value_decoded) == LEN_YYYYMMDDHHMMSSZ:
3034 datetime.strptime(value_decoded, self.fmt)
3037 "invalid GeneralizedTime (without ms) format",
3040 elif len(value_decoded) >= LEN_YYYYMMDDHHMMSSDMZ:
3042 datetime.strptime(value_decoded, self.fmt_ms)
3045 "invalid GeneralizedTime (with ms) format",
3050 "invalid GeneralizedTime length",
3051 klass=self.__class__,
3053 raise InvalidValueType((self.__class__, datetime))
3055 def todatetime(self):
3056 value = self._value.decode("ascii")
3057 if len(value) == LEN_YYYYMMDDHHMMSSZ:
3058 return datetime.strptime(value, self.fmt)
3059 return datetime.strptime(value, self.fmt_ms)
3062 class GraphicString(CommonString):
3064 tag_default = tag_encode(25)
3065 encoding = "iso-8859-1"
3066 asn1_type_name = "GraphicString"
3069 class VisibleString(CommonString):
3071 tag_default = tag_encode(26)
3073 asn1_type_name = "VisibleString"
3076 class ISO646String(VisibleString):
3078 asn1_type_name = "ISO646String"
3081 class GeneralString(CommonString):
3083 tag_default = tag_encode(27)
3084 encoding = "iso-8859-1"
3085 asn1_type_name = "GeneralString"
3088 class UniversalString(CommonString):
3090 tag_default = tag_encode(28)
3091 encoding = "utf-32-be"
3092 asn1_type_name = "UniversalString"
3095 class BMPString(CommonString):
3097 tag_default = tag_encode(30)
3098 encoding = "utf-16-be"
3099 asn1_type_name = "BMPString"
3103 """``CHOICE`` special type
3107 class GeneralName(Choice):
3109 ('rfc822Name', IA5String(impl=tag_ctxp(1))),
3110 ('dNSName', IA5String(impl=tag_ctxp(2))),
3113 >>> gn = GeneralName()
3115 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
3116 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3117 >>> gn["dNSName"] = IA5String("bar.baz")
3118 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
3119 >>> gn["rfc822Name"]
3122 [2] IA5String IA5 bar.baz
3125 >>> gn.value == gn["dNSName"]
3128 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
3130 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
3131 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3133 __slots__ = ("specs",)
3135 asn1_type_name = "CHOICE"
3148 :param value: set the value. Either ``(choice, value)`` tuple, or
3149 :py:class:`pyderasn.Choice` object
3150 :param bytes impl: can not be set, do **not** use it
3151 :param bytes expl: override default tag with ``EXPLICIT`` one
3152 :param default: set default value. Type same as in ``value``
3153 :param bool optional: is object ``OPTIONAL`` in sequence
3155 if impl is not None:
3156 raise ValueError("no implicit tag allowed for CHOICE")
3157 super(Choice, self).__init__(None, expl, default, optional, _decoded)
3159 schema = getattr(self, "schema", ())
3160 if len(schema) == 0:
3161 raise ValueError("schema must be specified")
3163 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
3166 if value is not None:
3167 self._value = self._value_sanitize(value)
3168 if default is not None:
3169 default_value = self._value_sanitize(default)
3170 default_obj = self.__class__(impl=self.tag, expl=self._expl)
3171 default_obj.specs = self.specs
3172 default_obj._value = default_value
3173 self.default = default_obj
3175 self._value = default_obj.copy()._value
3177 def _value_sanitize(self, value):
3178 if isinstance(value, self.__class__):
3180 if isinstance(value, tuple) and len(value) == 2:
3182 spec = self.specs.get(choice)
3184 raise ObjUnknown(choice)
3185 if not isinstance(obj, spec.__class__):
3186 raise InvalidValueType((spec,))
3187 return (choice, spec(obj))
3188 raise InvalidValueType((self.__class__, tuple))
3192 return self._value is not None and self._value[1].ready
3195 obj = self.__class__(schema=self.specs)
3196 obj._expl = self._expl
3197 obj.default = self.default
3198 obj.optional = self.optional
3199 obj.offset = self.offset
3200 obj.llen = self.llen
3201 obj.vlen = self.vlen
3203 if value is not None:
3204 obj._value = (value[0], value[1].copy())
3207 def __eq__(self, their):
3208 if isinstance(their, tuple) and len(their) == 2:
3209 return self._value == their
3210 if not isinstance(their, self.__class__):
3213 self.specs == their.specs and
3214 self._value == their._value
3224 return self.__class__(
3227 expl=self._expl if expl is None else expl,
3228 default=self.default if default is None else default,
3229 optional=self.optional if optional is None else optional,
3234 self._assert_ready()
3235 return self._value[0]
3239 self._assert_ready()
3240 return self._value[1]
3242 def __getitem__(self, key):
3243 if key not in self.specs:
3244 raise ObjUnknown(key)
3245 if self._value is None:
3247 choice, value = self._value
3252 def __setitem__(self, key, value):
3253 spec = self.specs.get(key)
3255 raise ObjUnknown(key)
3256 if not isinstance(value, spec.__class__):
3257 raise InvalidValueType((spec.__class__,))
3258 self._value = (key, spec(value))
3266 return self._value[1].decoded if self.ready else False
3269 self._assert_ready()
3270 return self._value[1].encode()
3272 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
3273 for choice, spec in self.specs.items():
3275 value, tail = spec.decode(
3279 decode_path=decode_path + (choice,),
3280 defines_by_path=defines_by_path,
3284 obj = self.__class__(
3287 default=self.default,
3288 optional=self.optional,
3289 _decoded=(offset, 0, value.tlvlen),
3291 obj._value = (choice, value)
3294 klass=self.__class__,
3295 decode_path=decode_path,
3300 value = pp_console_row(next(self.pps()))
3302 value = "%s[%r]" % (value, self.value)
3305 def pps(self, decode_path=()):
3307 asn1_type_name=self.asn1_type_name,
3308 obj_name=self.__class__.__name__,
3309 decode_path=decode_path,
3310 value=self.choice if self.ready else None,
3311 optional=self.optional,
3312 default=self == self.default,
3313 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3314 expl=None if self._expl is None else tag_decode(self._expl),
3321 yield self.value.pps(decode_path=decode_path + (self.choice,))
3324 class PrimitiveTypes(Choice):
3325 """Predefined ``CHOICE`` for all generic primitive types
3327 It could be useful for general decoding of some unspecified values:
3329 >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
3330 OCTET STRING 3 bytes 666f6f
3331 >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
3335 schema = tuple((klass.__name__, klass()) for klass in (
3360 """``ANY`` special type
3362 >>> Any(Integer(-123))
3364 >>> a = Any(OctetString(b"hello world").encode())
3365 ANY 040b68656c6c6f20776f726c64
3366 >>> hexenc(bytes(a))
3367 b'0x040x0bhello world'
3369 __slots__ = ("defined",)
3370 tag_default = tag_encode(0)
3371 asn1_type_name = "ANY"
3381 :param value: set the value. Either any kind of pyderasn's
3382 **ready** object, or bytes. Pay attention that
3383 **no** validation is performed is raw binary value
3385 :param bytes expl: override default tag with ``EXPLICIT`` one
3386 :param bool optional: is object ``OPTIONAL`` in sequence
3388 super(Any, self).__init__(None, expl, None, optional, _decoded)
3389 self._value = None if value is None else self._value_sanitize(value)
3392 def _value_sanitize(self, value):
3393 if isinstance(value, self.__class__):
3395 if isinstance(value, Obj):
3396 return value.encode()
3397 if isinstance(value, binary_type):
3399 raise InvalidValueType((self.__class__, Obj, binary_type))
3403 return self._value is not None
3406 obj = self.__class__()
3407 obj._value = self._value
3409 obj._expl = self._expl
3410 obj.optional = self.optional
3411 obj.offset = self.offset
3412 obj.llen = self.llen
3413 obj.vlen = self.vlen
3416 def __eq__(self, their):
3417 if isinstance(their, binary_type):
3418 return self._value == their
3419 if issubclass(their.__class__, Any):
3420 return self._value == their._value
3429 return self.__class__(
3431 expl=self._expl if expl is None else expl,
3432 optional=self.optional if optional is None else optional,
3435 def __bytes__(self):
3436 self._assert_ready()
3444 self._assert_ready()
3447 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
3449 t, tlen, lv = tag_strip(tlv)
3450 l, llen, v = len_decode(lv)
3451 except DecodeError as err:
3452 raise err.__class__(
3454 klass=self.__class__,
3455 decode_path=decode_path,
3459 raise NotEnoughData(
3460 "encoded length is longer than data",
3461 klass=self.__class__,
3462 decode_path=decode_path,
3465 tlvlen = tlen + llen + l
3466 v, tail = tlv[:tlvlen], v[l:]
3467 obj = self.__class__(
3470 optional=self.optional,
3471 _decoded=(offset, 0, tlvlen),
3477 return pp_console_row(next(self.pps()))
3479 def pps(self, decode_path=()):
3481 asn1_type_name=self.asn1_type_name,
3482 obj_name=self.__class__.__name__,
3483 decode_path=decode_path,
3484 blob=self._value if self.ready else None,
3485 optional=self.optional,
3486 default=self == self.default,
3487 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3488 expl=None if self._expl is None else tag_decode(self._expl),
3493 expl_offset=self.expl_offset if self.expled else None,
3494 expl_tlen=self.expl_tlen if self.expled else None,
3495 expl_llen=self.expl_llen if self.expled else None,
3496 expl_vlen=self.expl_vlen if self.expled else None,
3498 defined_by, defined = self.defined or (None, None)
3499 if defined_by is not None:
3501 decode_path=decode_path + (decode_path_defby(defined_by),)
3505 ########################################################################
3506 # ASN.1 constructed types
3507 ########################################################################
3509 def get_def_by_path(defines_by_path, sub_decode_path):
3510 """Get define by decode path
3512 for path, define in defines_by_path:
3513 if len(path) != len(sub_decode_path):
3515 for p1, p2 in zip(path, sub_decode_path):
3516 if (p1 != any) and (p1 != p2):
3522 class Sequence(Obj):
3523 """``SEQUENCE`` structure type
3525 You have to make specification of sequence::
3527 class Extension(Sequence):
3529 ("extnID", ObjectIdentifier()),
3530 ("critical", Boolean(default=False)),
3531 ("extnValue", OctetString()),
3534 Then, you can work with it as with dictionary.
3536 >>> ext = Extension()
3537 >>> Extension().specs
3539 ('extnID', OBJECT IDENTIFIER),
3540 ('critical', BOOLEAN False OPTIONAL DEFAULT),
3541 ('extnValue', OCTET STRING),
3543 >>> ext["extnID"] = "1.2.3"
3544 Traceback (most recent call last):
3545 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
3546 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
3548 You can know if sequence is ready to be encoded:
3553 Traceback (most recent call last):
3554 pyderasn.ObjNotReady: object is not ready: extnValue
3555 >>> ext["extnValue"] = OctetString(b"foobar")
3559 Value you want to assign, must have the same **type** as in
3560 corresponding specification, but it can have different tags,
3561 optional/default attributes -- they will be taken from specification
3564 class TBSCertificate(Sequence):
3566 ("version", Version(expl=tag_ctxc(0), default="v1")),
3569 >>> tbs = TBSCertificate()
3570 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
3572 You can know if value exists/set in the sequence and take its value:
3574 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
3577 OBJECT IDENTIFIER 1.2.3
3579 But pay attention that if value has default, then it won't be (not
3580 in) in the sequence (because ``DEFAULT`` must not be encoded in
3581 DER), but you can read its value:
3583 >>> "critical" in ext, ext["critical"]
3584 (False, BOOLEAN False)
3585 >>> ext["critical"] = Boolean(True)
3586 >>> "critical" in ext, ext["critical"]
3587 (True, BOOLEAN True)
3589 All defaulted values are always optional.
3593 When decoded DER contains defaulted value inside, then
3594 technically this is not valid DER encoding. But we allow
3595 and pass it. Of course reencoding of that kind of DER will
3596 result in different binary representation (validly without
3597 defaulted value inside).
3599 Two sequences are equal if they have equal specification (schema),
3600 implicit/explicit tagging and the same values.
3602 __slots__ = ("specs",)
3603 tag_default = tag_encode(form=TagFormConstructed, num=16)
3604 asn1_type_name = "SEQUENCE"
3616 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
3618 schema = getattr(self, "schema", ())
3620 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
3623 if value is not None:
3624 self._value = self._value_sanitize(value)
3625 if default is not None:
3626 default_value = self._value_sanitize(default)
3627 default_obj = self.__class__(impl=self.tag, expl=self._expl)
3628 default_obj.specs = self.specs
3629 default_obj._value = default_value
3630 self.default = default_obj
3632 self._value = default_obj.copy()._value
3634 def _value_sanitize(self, value):
3635 if not issubclass(value.__class__, Sequence):
3636 raise InvalidValueType((Sequence,))
3641 for name, spec in self.specs.items():
3642 value = self._value.get(name)
3653 obj = self.__class__(schema=self.specs)
3655 obj._expl = self._expl
3656 obj.default = self.default
3657 obj.optional = self.optional
3658 obj.offset = self.offset
3659 obj.llen = self.llen
3660 obj.vlen = self.vlen
3661 obj._value = {k: v.copy() for k, v in self._value.items()}
3664 def __eq__(self, their):
3665 if not isinstance(their, self.__class__):
3668 self.specs == their.specs and
3669 self.tag == their.tag and
3670 self._expl == their._expl and
3671 self._value == their._value
3682 return self.__class__(
3685 impl=self.tag if impl is None else impl,
3686 expl=self._expl if expl is None else expl,
3687 default=self.default if default is None else default,
3688 optional=self.optional if optional is None else optional,
3691 def __contains__(self, key):
3692 return key in self._value
3694 def __setitem__(self, key, value):
3695 spec = self.specs.get(key)
3697 raise ObjUnknown(key)
3699 self._value.pop(key, None)
3701 if not isinstance(value, spec.__class__):
3702 raise InvalidValueType((spec.__class__,))
3703 value = spec(value=value)
3704 if spec.default is not None and value == spec.default:
3705 self._value.pop(key, None)
3707 self._value[key] = value
3709 def __getitem__(self, key):
3710 value = self._value.get(key)
3711 if value is not None:
3713 spec = self.specs.get(key)
3715 raise ObjUnknown(key)
3716 if spec.default is not None:
3720 def _encoded_values(self):
3722 for name, spec in self.specs.items():
3723 value = self._value.get(name)
3727 raise ObjNotReady(name)
3728 raws.append(value.encode())
3732 v = b"".join(self._encoded_values())
3733 return b"".join((self.tag, len_encode(len(v)), v))
3735 def _decode(self, tlv, offset=0, decode_path=(), defines_by_path=None):
3737 t, tlen, lv = tag_strip(tlv)
3738 except DecodeError as err:
3739 raise err.__class__(
3741 klass=self.__class__,
3742 decode_path=decode_path,
3747 klass=self.__class__,
3748 decode_path=decode_path,
3752 l, llen, v = len_decode(lv)
3753 except DecodeError as err:
3754 raise err.__class__(
3756 klass=self.__class__,
3757 decode_path=decode_path,
3761 raise NotEnoughData(
3762 "encoded length is longer than data",
3763 klass=self.__class__,
3764 decode_path=decode_path,
3767 v, tail = v[:l], v[l:]
3768 sub_offset = offset + tlen + llen
3771 for name, spec in self.specs.items():
3772 if len(v) == 0 and spec.optional:
3774 sub_decode_path = decode_path + (name,)
3776 value, v_tail = spec.decode(
3780 decode_path=sub_decode_path,
3781 defines_by_path=defines_by_path,