3 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
4 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU Lesser General Public License as
8 # published by the Free Software Foundation, version 3 of the License.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see <http://www.gnu.org/licenses/>.
17 """Python ASN.1 DER/BER codec with abstract structures
19 This library allows you to marshal various structures in ASN.1 DER
20 format, unmarshal them in BER/CER/DER ones.
24 >>> Integer().decode(raw) == i
27 There are primitive types, holding single values
28 (:py:class:`pyderasn.BitString`,
29 :py:class:`pyderasn.Boolean`,
30 :py:class:`pyderasn.Enumerated`,
31 :py:class:`pyderasn.GeneralizedTime`,
32 :py:class:`pyderasn.Integer`,
33 :py:class:`pyderasn.Null`,
34 :py:class:`pyderasn.ObjectIdentifier`,
35 :py:class:`pyderasn.OctetString`,
36 :py:class:`pyderasn.UTCTime`,
37 :py:class:`various strings <pyderasn.CommonString>`
38 (:py:class:`pyderasn.BMPString`,
39 :py:class:`pyderasn.GeneralString`,
40 :py:class:`pyderasn.GraphicString`,
41 :py:class:`pyderasn.IA5String`,
42 :py:class:`pyderasn.ISO646String`,
43 :py:class:`pyderasn.NumericString`,
44 :py:class:`pyderasn.PrintableString`,
45 :py:class:`pyderasn.T61String`,
46 :py:class:`pyderasn.TeletexString`,
47 :py:class:`pyderasn.UniversalString`,
48 :py:class:`pyderasn.UTF8String`,
49 :py:class:`pyderasn.VideotexString`,
50 :py:class:`pyderasn.VisibleString`)),
51 constructed types, holding multiple primitive types
52 (:py:class:`pyderasn.Sequence`,
53 :py:class:`pyderasn.SequenceOf`,
54 :py:class:`pyderasn.Set`,
55 :py:class:`pyderasn.SetOf`),
56 and special types like
57 :py:class:`pyderasn.Any` and
58 :py:class:`pyderasn.Choice`.
66 Most types in ASN.1 has specific tag for them. ``Obj.tag_default`` is
67 the default tag used during coding process. You can override it with
68 either ``IMPLICIT`` (using either ``impl`` keyword argument or ``impl``
69 class attribute), or ``EXPLICIT`` one (using either ``expl`` keyword
70 argument or ``expl`` class attribute). Both arguments take raw binary
71 string, containing that tag. You can **not** set implicit and explicit
74 There are :py:func:`pyderasn.tag_ctxp` and :py:func:`pyderasn.tag_ctxc`
75 functions, allowing you to easily create ``CONTEXT``
76 ``PRIMITIVE``/``CONSTRUCTED`` tags, by specifying only the required tag
77 number. Pay attention that explicit tags always have *constructed* tag
78 (``tag_ctxc``), but implicit tags for primitive types are primitive
83 >>> Integer(impl=tag_ctxp(1))
85 >>> Integer(expl=tag_ctxc(2))
88 Implicit tag is not explicitly shown.
90 Two objects of the same type, but with different implicit/explicit tags
93 You can get object's effective tag (either default or implicited) through
94 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
97 >>> tag_decode(tag_ctxc(123))
99 >>> klass, form, num = tag_decode(tag_ctxc(123))
100 >>> klass == TagClassContext
102 >>> form == TagFormConstructed
105 To determine if object has explicit tag, use ``expled`` boolean property
106 and ``expl_tag`` property, returning explicit tag's value.
111 Many objects in sequences could be ``OPTIONAL`` and could have
112 ``DEFAULT`` value. You can specify that object's property using
113 corresponding keyword arguments.
115 >>> Integer(optional=True, default=123)
116 INTEGER 123 OPTIONAL DEFAULT
118 Those specifications do not play any role in primitive value encoding,
119 but are taken into account when dealing with sequences holding them. For
120 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
123 class Version(Integer):
129 class TBSCertificate(Sequence):
131 ("version", Version(expl=tag_ctxc(0), default="v1")),
134 When default argument is used and value is not specified, then it equals
142 Some objects give ability to set value size constraints. This is either
143 possible integer value, or allowed length of various strings and
144 sequences. Constraints are set in the following way::
149 And values satisfaction is checked as: ``MIN <= X <= MAX``.
151 For simplicity you can also set bounds the following way::
153 bounded_x = X(bounds=(MIN, MAX))
155 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
161 All objects have ``ready`` boolean property, that tells if object is
162 ready to be encoded. If that kind of action is performed on unready
163 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
165 All objects have ``copy()`` method, that returns their copy, that can be
173 Decoding is performed using ``decode()`` method. ``offset`` optional
174 argument could be used to set initial object's offset in the binary
175 data, for convenience. It returns decoded object and remaining
176 unmarshalled data (tail). Internally all work is done on
177 ``memoryview(data)``, and you can leave returning tail as a memoryview,
178 by specifying ``leavemm=True`` argument.
180 When object is decoded, ``decoded`` property is true and you can safely
181 use following properties:
183 * ``offset`` -- position including initial offset where object's tag starts
184 * ``tlen`` -- length of object's tag
185 * ``llen`` -- length of object's length value
186 * ``vlen`` -- length of object's value
187 * ``tlvlen`` -- length of the whole object
189 Pay attention that those values do **not** include anything related to
190 explicit tag. If you want to know information about it, then use:
192 * ``expled`` -- to know if explicit tag is set
193 * ``expl_offset`` (it is lesser than ``offset``)
196 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
197 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
199 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
202 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
209 You can specify so called context keyword argument during ``decode()``
210 invocation. It is dictionary containing various options governing
213 Currently available context options:
215 * :ref:`allow_default_values <allow_default_values_ctx>`
216 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
217 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
218 * :ref:`bered <bered_ctx>`
219 * :ref:`defines_by_path <defines_by_path_ctx>`
226 All objects have ``pps()`` method, that is a generator of
227 :py:class:`pyderasn.PP` namedtuple, holding various raw information
228 about the object. If ``pps`` is called on sequences, then all underlying
229 ``PP`` will be yielded.
231 You can use :py:func:`pyderasn.pp_console_row` function, converting
232 those ``PP`` to human readable string. Actually exactly it is used for
233 all object ``repr``. But it is easy to write custom formatters.
235 >>> from pyderasn import pprint
236 >>> encoded = Integer(-12345).encode()
237 >>> obj, tail = Integer().decode(encoded)
238 >>> print(pprint(obj))
239 0 [1,1, 2] INTEGER -12345
243 Example certificate::
245 >>> print(pprint(crt))
246 0 [1,3,1604] Certificate SEQUENCE
247 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
248 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
249 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
250 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
251 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
252 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
254 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
255 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
256 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
257 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
258 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
259 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
260 . . . . . . . 13:02:45:53
262 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
263 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
264 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
266 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
267 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
268 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
273 Let's parse that output, human::
275 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
276 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
277 0 1 2 3 4 5 6 7 8 9 10 11
281 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
287 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
293 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
298 Offset of the object, where its DER/BER encoding begins.
299 Pay attention that it does **not** include explicit tag.
301 If explicit tag exists, then this is its length (tag + encoded length).
303 Length of object's tag. For example CHOICE does not have its own tag,
306 Length of encoded length.
308 Length of encoded value.
310 Visual indentation to show the depth of object in the hierarchy.
312 Object's name inside SEQUENCE/CHOICE.
314 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
315 here. "IMPLICIT" is omitted.
317 Object's class name, if set. Omitted if it is just an ordinary simple
318 value (like with ``algorithm`` in example above).
322 Object's value, if set. Can consist of multiple words (like OCTET/BIT
323 STRINGs above). We see ``v3`` value in Version, because it is named.
324 ``rdnSequence`` is the choice of CHOICE type.
326 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
327 default one, specified in the schema.
329 Shows does object contains any kind of BER encoded data (possibly
330 Sequence holding BER-encoded underlying value).
332 Only applicable to BER encoded data. Indefinite length encoding mark.
334 Only applicable to BER encoded data. If object has BER-specific
335 encoding, then ``BER`` will be shown. It does not depend on indefinite
336 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
337 (and its derivatives), ``SET``, ``SET OF`` could be BERed.
345 ASN.1 structures often have ANY and OCTET STRING fields, that are
346 DEFINED BY some previously met ObjectIdentifier. This library provides
347 ability to specify mapping between some OID and field that must be
348 decoded with specific specification.
355 :py:class:`pyderasn.ObjectIdentifier` field inside
356 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
357 necessary for decoding structures. For example, CMS (:rfc:`5652`)
360 class ContentInfo(Sequence):
362 ("contentType", ContentType(defines=((("content",), {
363 id_digestedData: DigestedData(),
364 id_signedData: SignedData(),
366 ("content", Any(expl=tag_ctxc(0))),
369 ``contentType`` field tells that it defines that ``content`` must be
370 decoded with ``SignedData`` specification, if ``contentType`` equals to
371 ``id-signedData``. The same applies to ``DigestedData``. If
372 ``contentType`` contains unknown OID, then no automatic decoding is
375 You can specify multiple fields, that will be autodecoded -- that is why
376 ``defines`` kwarg is a sequence. You can specify defined field
377 relatively or absolutely to current decode path. For example ``defines``
378 for AlgorithmIdentifier of X.509's
379 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
383 id_ecPublicKey: ECParameters(),
384 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
386 (("..", "subjectPublicKey"), {
387 id_rsaEncryption: RSAPublicKey(),
388 id_GostR3410_2001: OctetString(),
392 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
393 autodecode its parameters inside SPKI's algorithm and its public key
396 Following types can be automatically decoded (DEFINED BY):
398 * :py:class:`pyderasn.Any`
399 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
400 * :py:class:`pyderasn.OctetString`
401 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
402 ``Any``/``BitString``/``OctetString``-s
404 When any of those fields is automatically decoded, then ``.defined``
405 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
406 was defined, ``value`` contains corresponding decoded value. For example
407 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
409 .. _defines_by_path_ctx:
411 defines_by_path context option
412 ______________________________
414 Sometimes you either can not or do not want to explicitly set *defines*
415 in the scheme. You can dynamically apply those definitions when calling
416 ``.decode()`` method.
418 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
419 value must be sequence of following tuples::
421 (decode_path, defines)
423 where ``decode_path`` is a tuple holding so-called decode path to the
424 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
425 ``defines``, holding exactly the same value as accepted in its
426 :ref:`keyword argument <defines>`.
428 For example, again for CMS, you want to automatically decode
429 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
430 structures it may hold. Also, automatically decode ``controlSequence``
433 content_info, tail = ContentInfo().decode(data, ctx={"defines_by_path": (
436 ((("content",), {id_signedData: SignedData()}),),
441 DecodePathDefBy(id_signedData),
446 id_cct_PKIData: PKIData(),
447 id_cct_PKIResponse: PKIResponse(),
453 DecodePathDefBy(id_signedData),
456 DecodePathDefBy(id_cct_PKIResponse),
462 id_cmc_recipientNonce: RecipientNonce(),
463 id_cmc_senderNonce: SenderNonce(),
464 id_cmc_statusInfoV2: CMCStatusInfoV2(),
465 id_cmc_transactionId: TransactionId(),
470 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
471 First function is useful for path construction when some automatic
472 decoding is already done. ``any`` means literally any value it meet --
473 useful for SEQUENCE/SET OF-s.
480 By default PyDERASN accepts only DER encoded data. It always encodes to
481 DER. But you can optionally enable BER decoding with setting ``bered``
482 :ref:`context <ctx>` argument to True. Indefinite lengths and
483 constructed primitive types should be parsed successfully.
485 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
486 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
487 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``
489 * If object has an indefinite length encoding, then its ``lenindef``
490 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
491 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
493 * If object has an indefinite length encoded explicit tag, then
494 ``expl_lenindef`` is set to True.
495 * If object has either any of BER-related encoding (explicit tag
496 indefinite length, object's indefinite length, BER-encoding) or any
497 underlying component has that kind of encoding, then ``bered``
498 attribute is set to True. For example SignedData CMS can have
499 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
500 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
502 EOC (end-of-contents) token's length is taken in advance in object's
505 .. _allow_expl_oob_ctx:
507 Allow explicit tag out-of-bound
508 -------------------------------
510 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
511 one value, more than one object. If you set ``allow_expl_oob`` context
512 option to True, then no error will be raised and that invalid encoding
513 will be silently further processed. But pay attention that offsets and
514 lengths will be invalid in that case.
518 This option should be used only for skipping some decode errors, just
519 to see the decoded structure somehow.
523 .. autoclass:: pyderasn.Obj
531 .. autoclass:: pyderasn.Boolean
536 .. autoclass:: pyderasn.Integer
541 .. autoclass:: pyderasn.BitString
546 .. autoclass:: pyderasn.OctetString
551 .. autoclass:: pyderasn.Null
556 .. autoclass:: pyderasn.ObjectIdentifier
561 .. autoclass:: pyderasn.Enumerated
565 .. autoclass:: pyderasn.CommonString
569 .. autoclass:: pyderasn.NumericString
573 .. autoclass:: pyderasn.PrintableString
578 .. autoclass:: pyderasn.UTCTime
579 :members: __init__, todatetime
583 .. autoclass:: pyderasn.GeneralizedTime
590 .. autoclass:: pyderasn.Choice
595 .. autoclass:: PrimitiveTypes
599 .. autoclass:: pyderasn.Any
607 .. autoclass:: pyderasn.Sequence
612 .. autoclass:: pyderasn.Set
617 .. autoclass:: pyderasn.SequenceOf
622 .. autoclass:: pyderasn.SetOf
628 .. autofunction:: pyderasn.abs_decode_path
629 .. autofunction:: pyderasn.colonize_hex
630 .. autofunction:: pyderasn.hexenc
631 .. autofunction:: pyderasn.hexdec
632 .. autofunction:: pyderasn.tag_encode
633 .. autofunction:: pyderasn.tag_decode
634 .. autofunction:: pyderasn.tag_ctxp
635 .. autofunction:: pyderasn.tag_ctxc
636 .. autoclass:: pyderasn.DecodeError
638 .. autoclass:: pyderasn.NotEnoughData
639 .. autoclass:: pyderasn.ExceedingData
640 .. autoclass:: pyderasn.LenIndefForm
641 .. autoclass:: pyderasn.TagMismatch
642 .. autoclass:: pyderasn.InvalidLength
643 .. autoclass:: pyderasn.InvalidOID
644 .. autoclass:: pyderasn.ObjUnknown
645 .. autoclass:: pyderasn.ObjNotReady
646 .. autoclass:: pyderasn.InvalidValueType
647 .. autoclass:: pyderasn.BoundsError
650 from codecs import getdecoder
651 from codecs import getencoder
652 from collections import namedtuple
653 from collections import OrderedDict
654 from copy import copy
655 from datetime import datetime
656 from math import ceil
657 from os import environ
658 from string import ascii_letters
659 from string import digits
660 from unicodedata import category as unicat
662 from six import add_metaclass
663 from six import binary_type
664 from six import byte2int
665 from six import indexbytes
666 from six import int2byte
667 from six import integer_types
668 from six import iterbytes
669 from six import iteritems
670 from six import itervalues
672 from six import string_types
673 from six import text_type
674 from six import unichr as six_unichr
675 from six.moves import xrange as six_xrange
679 from termcolor import colored
680 except ImportError: # pragma: no cover
681 def colored(what, *args, **kwargs):
727 "TagClassApplication",
731 "TagFormConstructed",
742 TagClassUniversal = 0
743 TagClassApplication = 1 << 6
744 TagClassContext = 1 << 7
745 TagClassPrivate = 1 << 6 | 1 << 7
747 TagFormConstructed = 1 << 5
750 TagClassApplication: "APPLICATION ",
751 TagClassPrivate: "PRIVATE ",
752 TagClassUniversal: "UNIV ",
756 LENINDEF = b"\x80" # length indefinite mark
757 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
760 ########################################################################
762 ########################################################################
764 class ASN1Error(ValueError):
768 class DecodeError(ASN1Error):
769 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
771 :param str msg: reason of decode failing
772 :param klass: optional exact DecodeError inherited class (like
773 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
774 :py:exc:`InvalidLength`)
775 :param decode_path: tuple of strings. It contains human
776 readable names of the fields through which
777 decoding process has passed
778 :param int offset: binary offset where failure happened
780 super(DecodeError, self).__init__()
783 self.decode_path = decode_path
789 "" if self.klass is None else self.klass.__name__,
791 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
792 if len(self.decode_path) > 0 else ""
794 ("(at %d)" % self.offset) if self.offset > 0 else "",
800 return "%s(%s)" % (self.__class__.__name__, self)
803 class NotEnoughData(DecodeError):
807 class ExceedingData(ASN1Error):
808 def __init__(self, nbytes):
809 super(ExceedingData, self).__init__()
813 return "%d trailing bytes" % self.nbytes
816 return "%s(%s)" % (self.__class__.__name__, self)
819 class LenIndefForm(DecodeError):
823 class TagMismatch(DecodeError):
827 class InvalidLength(DecodeError):
831 class InvalidOID(DecodeError):
835 class ObjUnknown(ASN1Error):
836 def __init__(self, name):
837 super(ObjUnknown, self).__init__()
841 return "object is unknown: %s" % self.name
844 return "%s(%s)" % (self.__class__.__name__, self)
847 class ObjNotReady(ASN1Error):
848 def __init__(self, name):
849 super(ObjNotReady, self).__init__()
853 return "object is not ready: %s" % self.name
856 return "%s(%s)" % (self.__class__.__name__, self)
859 class InvalidValueType(ASN1Error):
860 def __init__(self, expected_types):
861 super(InvalidValueType, self).__init__()
862 self.expected_types = expected_types
865 return "invalid value type, expected: %s" % ", ".join(
866 [repr(t) for t in self.expected_types]
870 return "%s(%s)" % (self.__class__.__name__, self)
873 class BoundsError(ASN1Error):
874 def __init__(self, bound_min, value, bound_max):
875 super(BoundsError, self).__init__()
876 self.bound_min = bound_min
878 self.bound_max = bound_max
881 return "unsatisfied bounds: %s <= %s <= %s" % (
888 return "%s(%s)" % (self.__class__.__name__, self)
891 ########################################################################
893 ########################################################################
895 _hexdecoder = getdecoder("hex")
896 _hexencoder = getencoder("hex")
900 """Binary data to hexadecimal string convert
902 return _hexdecoder(data)[0]
906 """Hexadecimal string to binary data convert
908 return _hexencoder(data)[0].decode("ascii")
911 def int_bytes_len(num, byte_len=8):
914 return int(ceil(float(num.bit_length()) / byte_len))
917 def zero_ended_encode(num):
918 octets = bytearray(int_bytes_len(num, 7))
920 octets[i] = num & 0x7F
924 octets[i] = 0x80 | (num & 0x7F)
930 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
931 """Encode tag to binary form
933 :param int num: tag's number
934 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
935 :py:data:`pyderasn.TagClassContext`,
936 :py:data:`pyderasn.TagClassApplication`,
937 :py:data:`pyderasn.TagClassPrivate`)
938 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
939 :py:data:`pyderasn.TagFormConstructed`)
943 return int2byte(klass | form | num)
944 # [XX|X|11111][1.......][1.......] ... [0.......]
945 return int2byte(klass | form | 31) + zero_ended_encode(num)
949 """Decode tag from binary form
953 No validation is performed, assuming that it has already passed.
955 It returns tuple with three integers, as
956 :py:func:`pyderasn.tag_encode` accepts.
958 first_octet = byte2int(tag)
959 klass = first_octet & 0xC0
960 form = first_octet & 0x20
961 if first_octet & 0x1F < 0x1F:
962 return (klass, form, first_octet & 0x1F)
964 for octet in iterbytes(tag[1:]):
967 return (klass, form, num)
971 """Create CONTEXT PRIMITIVE tag
973 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
977 """Create CONTEXT CONSTRUCTED tag
979 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
983 """Take off tag from the data
985 :returns: (encoded tag, tag length, remaining data)
988 raise NotEnoughData("no data at all")
989 if byte2int(data) & 0x1F < 31:
990 return data[:1], 1, data[1:]
995 raise DecodeError("unfinished tag")
996 if indexbytes(data, i) & 0x80 == 0:
999 return data[:i], i, data[i:]
1005 octets = bytearray(int_bytes_len(l) + 1)
1006 octets[0] = 0x80 | (len(octets) - 1)
1007 for i in six_xrange(len(octets) - 1, 0, -1):
1008 octets[i] = l & 0xFF
1010 return bytes(octets)
1013 def len_decode(data):
1016 :returns: (decoded length, length's length, remaining data)
1017 :raises LenIndefForm: if indefinite form encoding is met
1020 raise NotEnoughData("no data at all")
1021 first_octet = byte2int(data)
1022 if first_octet & 0x80 == 0:
1023 return first_octet, 1, data[1:]
1024 octets_num = first_octet & 0x7F
1025 if octets_num + 1 > len(data):
1026 raise NotEnoughData("encoded length is longer than data")
1028 raise LenIndefForm()
1029 if byte2int(data[1:]) == 0:
1030 raise DecodeError("leading zeros")
1032 for v in iterbytes(data[1:1 + octets_num]):
1035 raise DecodeError("long form instead of short one")
1036 return l, 1 + octets_num, data[1 + octets_num:]
1039 ########################################################################
1041 ########################################################################
1043 class AutoAddSlots(type):
1044 def __new__(cls, name, bases, _dict):
1045 _dict["__slots__"] = _dict.get("__slots__", ())
1046 return type.__new__(cls, name, bases, _dict)
1049 @add_metaclass(AutoAddSlots)
1051 """Common ASN.1 object class
1053 All ASN.1 types are inherited from it. It has metaclass that
1054 automatically adds ``__slots__`` to all inherited classes.
1078 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1079 self._expl = getattr(self, "expl", None) if expl is None else expl
1080 if self.tag != self.tag_default and self._expl is not None:
1081 raise ValueError("implicit and explicit tags can not be set simultaneously")
1082 if default is not None:
1084 self.optional = optional
1085 self.offset, self.llen, self.vlen = _decoded
1087 self.expl_lenindef = False
1088 self.lenindef = False
1089 self.ber_encoded = False
1092 def ready(self): # pragma: no cover
1093 """Is object ready to be encoded?
1095 raise NotImplementedError()
1097 def _assert_ready(self):
1099 raise ObjNotReady(self.__class__.__name__)
1103 """Is either object or any elements inside is BER encoded?
1105 return self.expl_lenindef or self.lenindef or self.ber_encoded
1109 """Is object decoded?
1111 return (self.llen + self.vlen) > 0
1113 def copy(self): # pragma: no cover
1114 """Make a copy of object, safe to be mutated
1116 raise NotImplementedError()
1120 """See :ref:`decoding`
1122 return len(self.tag)
1126 """See :ref:`decoding`
1128 return self.tlen + self.llen + self.vlen
1130 def __str__(self): # pragma: no cover
1131 return self.__bytes__() if PY2 else self.__unicode__()
1133 def __ne__(self, their):
1134 return not(self == their)
1136 def __gt__(self, their): # pragma: no cover
1137 return not(self < their)
1139 def __le__(self, their): # pragma: no cover
1140 return (self == their) or (self < their)
1142 def __ge__(self, their): # pragma: no cover
1143 return (self == their) or (self > their)
1145 def _encode(self): # pragma: no cover
1146 raise NotImplementedError()
1148 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1149 raise NotImplementedError()
1152 """Encode the structure
1154 :returns: DER representation
1156 raw = self._encode()
1157 if self._expl is None:
1159 return b"".join((self._expl, len_encode(len(raw)), raw))
1169 _ctx_immutable=True,
1173 :param data: either binary or memoryview
1174 :param int offset: initial data's offset
1175 :param bool leavemm: do we need to leave memoryview of remaining
1176 data as is, or convert it to bytes otherwise
1177 :param ctx: optional :ref:`context <ctx>` governing decoding process
1178 :param tag_only: decode only the tag, without length and contents
1179 (used only in Choice and Set structures, trying to
1180 determine if tag satisfies the scheme)
1181 :param _ctx_immutable: do we need to copy ``ctx`` before using it
1182 :returns: (Obj, remaining data)
1184 .. seealso:: :ref:`decoding`
1188 elif _ctx_immutable:
1190 tlv = memoryview(data)
1191 if self._expl is None:
1192 result = self._decode(
1195 decode_path=decode_path,
1204 t, tlen, lv = tag_strip(tlv)
1205 except DecodeError as err:
1206 raise err.__class__(
1208 klass=self.__class__,
1209 decode_path=decode_path,
1214 klass=self.__class__,
1215 decode_path=decode_path,
1219 l, llen, v = len_decode(lv)
1220 except LenIndefForm as err:
1221 if not ctx.get("bered", False):
1222 raise err.__class__(
1224 klass=self.__class__,
1225 decode_path=decode_path,
1229 offset += tlen + llen
1230 result = self._decode(
1233 decode_path=decode_path,
1237 if tag_only: # pragma: no cover
1240 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1241 if eoc_expected.tobytes() != EOC:
1244 klass=self.__class__,
1245 decode_path=decode_path,
1249 obj.expl_lenindef = True
1250 except DecodeError as err:
1251 raise err.__class__(
1253 klass=self.__class__,
1254 decode_path=decode_path,
1259 raise NotEnoughData(
1260 "encoded length is longer than data",
1261 klass=self.__class__,
1262 decode_path=decode_path,
1265 result = self._decode(
1267 offset=offset + tlen + llen,
1268 decode_path=decode_path,
1272 if tag_only: # pragma: no cover
1275 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1277 "explicit tag out-of-bound, longer than data",
1278 klass=self.__class__,
1279 decode_path=decode_path,
1282 return obj, (tail if leavemm else tail.tobytes())
1284 def decod(self, data, offset=0, decode_path=(), ctx=None):
1285 """Decode the data, check that tail is empty
1287 :raises ExceedingData: if tail is not empty
1289 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1290 (decode without tail) that also checks that there is no
1293 obj, tail = self.decode(
1296 decode_path=decode_path,
1301 raise ExceedingData(len(tail))
1306 """See :ref:`decoding`
1308 return self._expl is not None
1312 """See :ref:`decoding`
1317 def expl_tlen(self):
1318 """See :ref:`decoding`
1320 return len(self._expl)
1323 def expl_llen(self):
1324 """See :ref:`decoding`
1326 if self.expl_lenindef:
1328 return len(len_encode(self.tlvlen))
1331 def expl_offset(self):
1332 """See :ref:`decoding`
1334 return self.offset - self.expl_tlen - self.expl_llen
1337 def expl_vlen(self):
1338 """See :ref:`decoding`
1343 def expl_tlvlen(self):
1344 """See :ref:`decoding`
1346 return self.expl_tlen + self.expl_llen + self.expl_vlen
1349 def fulloffset(self):
1350 """See :ref:`decoding`
1352 return self.expl_offset if self.expled else self.offset
1356 """See :ref:`decoding`
1358 return self.expl_tlvlen if self.expled else self.tlvlen
1360 def pps_lenindef(self, decode_path):
1361 if self.lenindef and not (
1362 getattr(self, "defined", None) is not None and
1363 self.defined[1].lenindef
1366 asn1_type_name="EOC",
1368 decode_path=decode_path,
1370 self.offset + self.tlvlen -
1371 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1379 if self.expl_lenindef:
1381 asn1_type_name="EOC",
1382 obj_name="EXPLICIT",
1383 decode_path=decode_path,
1384 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1393 class DecodePathDefBy(object):
1394 """DEFINED BY representation inside decode path
1396 __slots__ = ("defined_by",)
1398 def __init__(self, defined_by):
1399 self.defined_by = defined_by
1401 def __ne__(self, their):
1402 return not(self == their)
1404 def __eq__(self, their):
1405 if not isinstance(their, self.__class__):
1407 return self.defined_by == their.defined_by
1410 return "DEFINED BY " + str(self.defined_by)
1413 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1416 ########################################################################
1418 ########################################################################
1420 PP = namedtuple("PP", (
1448 asn1_type_name="unknown",
1465 expl_lenindef=False,
1496 def _colourize(what, colour, with_colours, attrs=("bold",)):
1497 return colored(what, colour, attrs=attrs) if with_colours else what
1500 def colonize_hex(hexed):
1501 """Separate hexadecimal string with colons
1503 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1512 with_decode_path=False,
1513 decode_path_len_decrease=0,
1520 " " if pp.expl_offset is None else
1521 ("-%d" % (pp.offset - pp.expl_offset))
1523 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1525 col = _colourize(col, "red", with_colours, ())
1526 col += _colourize("B", "red", with_colours) if pp.bered else " "
1528 col = "[%d,%d,%4d]%s" % (
1532 LENINDEF_PP_CHAR if pp.lenindef else " "
1534 col = _colourize(col, "green", with_colours, ())
1536 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1537 if decode_path_len > 0:
1538 cols.append(" ." * decode_path_len)
1539 ent = pp.decode_path[-1]
1540 if isinstance(ent, DecodePathDefBy):
1541 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1542 value = str(ent.defined_by)
1545 len(oid_maps) > 0 and
1546 ent.defined_by.asn1_type_name ==
1547 ObjectIdentifier.asn1_type_name
1549 for oid_map in oid_maps:
1550 oid_name = oid_map.get(value)
1551 if oid_name is not None:
1552 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1554 if oid_name is None:
1555 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1557 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1558 if pp.expl is not None:
1559 klass, _, num = pp.expl
1560 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1561 cols.append(_colourize(col, "blue", with_colours))
1562 if pp.impl is not None:
1563 klass, _, num = pp.impl
1564 col = "[%s%d]" % (TagClassReprs[klass], num)
1565 cols.append(_colourize(col, "blue", with_colours))
1566 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1567 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1569 cols.append(_colourize("BER", "red", with_colours))
1570 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1571 if pp.value is not None:
1573 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1575 len(oid_maps) > 0 and
1576 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1578 for oid_map in oid_maps:
1579 oid_name = oid_map.get(value)
1580 if oid_name is not None:
1581 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1583 if pp.asn1_type_name == Integer.asn1_type_name:
1584 hex_repr = hex(int(pp.obj._value))[2:].upper()
1585 if len(hex_repr) % 2 != 0:
1586 hex_repr = "0" + hex_repr
1587 cols.append(_colourize(
1588 "(%s)" % colonize_hex(hex_repr),
1593 if isinstance(pp.blob, binary_type):
1594 cols.append(hexenc(pp.blob))
1595 elif isinstance(pp.blob, tuple):
1596 cols.append(", ".join(pp.blob))
1598 cols.append(_colourize("OPTIONAL", "red", with_colours))
1600 cols.append(_colourize("DEFAULT", "red", with_colours))
1601 if with_decode_path:
1602 cols.append(_colourize(
1603 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1607 return " ".join(cols)
1610 def pp_console_blob(pp, decode_path_len_decrease=0):
1611 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1612 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1613 if decode_path_len > 0:
1614 cols.append(" ." * (decode_path_len + 1))
1615 if isinstance(pp.blob, binary_type):
1616 blob = hexenc(pp.blob).upper()
1617 for i in six_xrange(0, len(blob), 32):
1618 chunk = blob[i:i + 32]
1619 yield " ".join(cols + [colonize_hex(chunk)])
1620 elif isinstance(pp.blob, tuple):
1621 yield " ".join(cols + [", ".join(pp.blob)])
1629 with_decode_path=False,
1630 decode_path_only=(),
1632 """Pretty print object
1634 :param Obj obj: object you want to pretty print
1635 :param oid_maps: list of ``OID <-> humand readable string`` dictionary.
1636 When OID from it is met, then its humand readable form
1638 :param big_blobs: if large binary objects are met (like OctetString
1639 values), do we need to print them too, on separate
1641 :param with_colours: colourize output, if ``termcolor`` library
1643 :param with_decode_path: print decode path
1644 :param decode_path_only: print only that specified decode path
1646 def _pprint_pps(pps):
1648 if hasattr(pp, "_fields"):
1650 decode_path_only != () and
1652 str(p) for p in pp.decode_path[:len(decode_path_only)]
1653 ) != decode_path_only
1657 yield pp_console_row(
1662 with_colours=with_colours,
1663 with_decode_path=with_decode_path,
1664 decode_path_len_decrease=len(decode_path_only),
1666 for row in pp_console_blob(
1668 decode_path_len_decrease=len(decode_path_only),
1672 yield pp_console_row(
1677 with_colours=with_colours,
1678 with_decode_path=with_decode_path,
1679 decode_path_len_decrease=len(decode_path_only),
1682 for row in _pprint_pps(pp):
1684 return "\n".join(_pprint_pps(obj.pps()))
1687 ########################################################################
1688 # ASN.1 primitive types
1689 ########################################################################
1692 """``BOOLEAN`` boolean type
1694 >>> b = Boolean(True)
1696 >>> b == Boolean(True)
1702 tag_default = tag_encode(1)
1703 asn1_type_name = "BOOLEAN"
1715 :param value: set the value. Either boolean type, or
1716 :py:class:`pyderasn.Boolean` object
1717 :param bytes impl: override default tag with ``IMPLICIT`` one
1718 :param bytes expl: override default tag with ``EXPLICIT`` one
1719 :param default: set default value. Type same as in ``value``
1720 :param bool optional: is object ``OPTIONAL`` in sequence
1722 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1723 self._value = None if value is None else self._value_sanitize(value)
1724 if default is not None:
1725 default = self._value_sanitize(default)
1726 self.default = self.__class__(
1732 self._value = default
1734 def _value_sanitize(self, value):
1735 if isinstance(value, bool):
1737 if issubclass(value.__class__, Boolean):
1739 raise InvalidValueType((self.__class__, bool))
1743 return self._value is not None
1746 obj = self.__class__()
1747 obj._value = self._value
1749 obj._expl = self._expl
1750 obj.default = self.default
1751 obj.optional = self.optional
1752 obj.offset = self.offset
1753 obj.llen = self.llen
1754 obj.vlen = self.vlen
1755 obj.expl_lenindef = self.expl_lenindef
1756 obj.lenindef = self.lenindef
1757 obj.ber_encoded = self.ber_encoded
1760 def __nonzero__(self):
1761 self._assert_ready()
1765 self._assert_ready()
1768 def __eq__(self, their):
1769 if isinstance(their, bool):
1770 return self._value == their
1771 if not issubclass(their.__class__, Boolean):
1774 self._value == their._value and
1775 self.tag == their.tag and
1776 self._expl == their._expl
1787 return self.__class__(
1789 impl=self.tag if impl is None else impl,
1790 expl=self._expl if expl is None else expl,
1791 default=self.default if default is None else default,
1792 optional=self.optional if optional is None else optional,
1796 self._assert_ready()
1800 (b"\xFF" if self._value else b"\x00"),
1803 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1805 t, _, lv = tag_strip(tlv)
1806 except DecodeError as err:
1807 raise err.__class__(
1809 klass=self.__class__,
1810 decode_path=decode_path,
1815 klass=self.__class__,
1816 decode_path=decode_path,
1822 l, _, v = len_decode(lv)
1823 except DecodeError as err:
1824 raise err.__class__(
1826 klass=self.__class__,
1827 decode_path=decode_path,
1831 raise InvalidLength(
1832 "Boolean's length must be equal to 1",
1833 klass=self.__class__,
1834 decode_path=decode_path,
1838 raise NotEnoughData(
1839 "encoded length is longer than data",
1840 klass=self.__class__,
1841 decode_path=decode_path,
1844 first_octet = byte2int(v)
1846 if first_octet == 0:
1848 elif first_octet == 0xFF:
1850 elif ctx.get("bered", False):
1855 "unacceptable Boolean value",
1856 klass=self.__class__,
1857 decode_path=decode_path,
1860 obj = self.__class__(
1864 default=self.default,
1865 optional=self.optional,
1866 _decoded=(offset, 1, 1),
1868 obj.ber_encoded = ber_encoded
1872 return pp_console_row(next(self.pps()))
1874 def pps(self, decode_path=()):
1877 asn1_type_name=self.asn1_type_name,
1878 obj_name=self.__class__.__name__,
1879 decode_path=decode_path,
1880 value=str(self._value) if self.ready else None,
1881 optional=self.optional,
1882 default=self == self.default,
1883 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1884 expl=None if self._expl is None else tag_decode(self._expl),
1889 expl_offset=self.expl_offset if self.expled else None,
1890 expl_tlen=self.expl_tlen if self.expled else None,
1891 expl_llen=self.expl_llen if self.expled else None,
1892 expl_vlen=self.expl_vlen if self.expled else None,
1893 expl_lenindef=self.expl_lenindef,
1894 ber_encoded=self.ber_encoded,
1897 for pp in self.pps_lenindef(decode_path):
1902 """``INTEGER`` integer type
1904 >>> b = Integer(-123)
1906 >>> b == Integer(-123)
1911 >>> Integer(2, bounds=(1, 3))
1913 >>> Integer(5, bounds=(1, 3))
1914 Traceback (most recent call last):
1915 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1919 class Version(Integer):
1926 >>> v = Version("v1")
1933 {'v3': 2, 'v1': 0, 'v2': 1}
1935 __slots__ = ("specs", "_bound_min", "_bound_max")
1936 tag_default = tag_encode(2)
1937 asn1_type_name = "INTEGER"
1951 :param value: set the value. Either integer type, named value
1952 (if ``schema`` is specified in the class), or
1953 :py:class:`pyderasn.Integer` object
1954 :param bounds: set ``(MIN, MAX)`` value constraint.
1955 (-inf, +inf) by default
1956 :param bytes impl: override default tag with ``IMPLICIT`` one
1957 :param bytes expl: override default tag with ``EXPLICIT`` one
1958 :param default: set default value. Type same as in ``value``
1959 :param bool optional: is object ``OPTIONAL`` in sequence
1961 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
1963 specs = getattr(self, "schema", {}) if _specs is None else _specs
1964 self.specs = specs if isinstance(specs, dict) else dict(specs)
1965 self._bound_min, self._bound_max = getattr(
1968 (float("-inf"), float("+inf")),
1969 ) if bounds is None else bounds
1970 if value is not None:
1971 self._value = self._value_sanitize(value)
1972 if default is not None:
1973 default = self._value_sanitize(default)
1974 self.default = self.__class__(
1980 if self._value is None:
1981 self._value = default
1983 def _value_sanitize(self, value):
1984 if isinstance(value, integer_types):
1986 elif issubclass(value.__class__, Integer):
1987 value = value._value
1988 elif isinstance(value, str):
1989 value = self.specs.get(value)
1991 raise ObjUnknown("integer value: %s" % value)
1993 raise InvalidValueType((self.__class__, int, str))
1994 if not self._bound_min <= value <= self._bound_max:
1995 raise BoundsError(self._bound_min, value, self._bound_max)
2000 return self._value is not None
2003 obj = self.__class__(_specs=self.specs)
2004 obj._value = self._value
2005 obj._bound_min = self._bound_min
2006 obj._bound_max = self._bound_max
2008 obj._expl = self._expl
2009 obj.default = self.default
2010 obj.optional = self.optional
2011 obj.offset = self.offset
2012 obj.llen = self.llen
2013 obj.vlen = self.vlen
2014 obj.expl_lenindef = self.expl_lenindef
2015 obj.lenindef = self.lenindef
2016 obj.ber_encoded = self.ber_encoded
2020 self._assert_ready()
2021 return int(self._value)
2024 self._assert_ready()
2027 bytes(self._expl or b"") +
2028 str(self._value).encode("ascii"),
2031 def __eq__(self, their):
2032 if isinstance(their, integer_types):
2033 return self._value == their
2034 if not issubclass(their.__class__, Integer):
2037 self._value == their._value and
2038 self.tag == their.tag and
2039 self._expl == their._expl
2042 def __lt__(self, their):
2043 return self._value < their._value
2047 for name, value in iteritems(self.specs):
2048 if value == self._value:
2061 return self.__class__(
2064 (self._bound_min, self._bound_max)
2065 if bounds is None else bounds
2067 impl=self.tag if impl is None else impl,
2068 expl=self._expl if expl is None else expl,
2069 default=self.default if default is None else default,
2070 optional=self.optional if optional is None else optional,
2075 self._assert_ready()
2079 octets = bytearray([0])
2083 octets = bytearray()
2085 octets.append((value & 0xFF) ^ 0xFF)
2087 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2090 octets = bytearray()
2092 octets.append(value & 0xFF)
2094 if octets[-1] & 0x80 > 0:
2097 octets = bytes(octets)
2099 bytes_len = ceil(value.bit_length() / 8) or 1
2102 octets = value.to_bytes(
2107 except OverflowError:
2111 return b"".join((self.tag, len_encode(len(octets)), octets))
2113 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
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,
2132 l, llen, v = len_decode(lv)
2133 except DecodeError as err:
2134 raise err.__class__(
2136 klass=self.__class__,
2137 decode_path=decode_path,
2141 raise NotEnoughData(
2142 "encoded length is longer than data",
2143 klass=self.__class__,
2144 decode_path=decode_path,
2148 raise NotEnoughData(
2150 klass=self.__class__,
2151 decode_path=decode_path,
2154 v, tail = v[:l], v[l:]
2155 first_octet = byte2int(v)
2157 second_octet = byte2int(v[1:])
2159 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2160 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2163 "non normalized integer",
2164 klass=self.__class__,
2165 decode_path=decode_path,
2170 if first_octet & 0x80 > 0:
2171 octets = bytearray()
2172 for octet in bytearray(v):
2173 octets.append(octet ^ 0xFF)
2174 for octet in octets:
2175 value = (value << 8) | octet
2179 for octet in bytearray(v):
2180 value = (value << 8) | octet
2182 value = int.from_bytes(v, byteorder="big", signed=True)
2184 obj = self.__class__(
2186 bounds=(self._bound_min, self._bound_max),
2189 default=self.default,
2190 optional=self.optional,
2192 _decoded=(offset, llen, l),
2194 except BoundsError as err:
2197 klass=self.__class__,
2198 decode_path=decode_path,
2204 return pp_console_row(next(self.pps()))
2206 def pps(self, decode_path=()):
2209 asn1_type_name=self.asn1_type_name,
2210 obj_name=self.__class__.__name__,
2211 decode_path=decode_path,
2212 value=(self.named or str(self._value)) if self.ready else None,
2213 optional=self.optional,
2214 default=self == self.default,
2215 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2216 expl=None if self._expl is None else tag_decode(self._expl),
2221 expl_offset=self.expl_offset if self.expled else None,
2222 expl_tlen=self.expl_tlen if self.expled else None,
2223 expl_llen=self.expl_llen if self.expled else None,
2224 expl_vlen=self.expl_vlen if self.expled else None,
2225 expl_lenindef=self.expl_lenindef,
2228 for pp in self.pps_lenindef(decode_path):
2232 SET01 = frozenset(("0", "1"))
2235 class BitString(Obj):
2236 """``BIT STRING`` bit string type
2238 >>> BitString(b"hello world")
2239 BIT STRING 88 bits 68656c6c6f20776f726c64
2242 >>> b == b"hello world"
2247 >>> BitString("'0A3B5F291CD'H")
2248 BIT STRING 44 bits 0a3b5f291cd0
2249 >>> b = BitString("'010110000000'B")
2250 BIT STRING 12 bits 5800
2253 >>> b[0], b[1], b[2], b[3]
2254 (False, True, False, True)
2258 [False, True, False, True, True, False, False, False, False, False, False, False]
2262 class KeyUsage(BitString):
2264 ("digitalSignature", 0),
2265 ("nonRepudiation", 1),
2266 ("keyEncipherment", 2),
2269 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2270 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2272 ['nonRepudiation', 'keyEncipherment']
2274 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2278 Pay attention that BIT STRING can be encoded both in primitive
2279 and constructed forms. Decoder always checks constructed form tag
2280 additionally to specified primitive one. If BER decoding is
2281 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2282 of DER restrictions.
2284 __slots__ = ("tag_constructed", "specs", "defined")
2285 tag_default = tag_encode(3)
2286 asn1_type_name = "BIT STRING"
2299 :param value: set the value. Either binary type, tuple of named
2300 values (if ``schema`` is specified in the class),
2301 string in ``'XXX...'B`` form, or
2302 :py:class:`pyderasn.BitString` object
2303 :param bytes impl: override default tag with ``IMPLICIT`` one
2304 :param bytes expl: override default tag with ``EXPLICIT`` one
2305 :param default: set default value. Type same as in ``value``
2306 :param bool optional: is object ``OPTIONAL`` in sequence
2308 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2309 specs = getattr(self, "schema", {}) if _specs is None else _specs
2310 self.specs = specs if isinstance(specs, dict) else dict(specs)
2311 self._value = None if value is None else self._value_sanitize(value)
2312 if default is not None:
2313 default = self._value_sanitize(default)
2314 self.default = self.__class__(
2320 self._value = default
2322 tag_klass, _, tag_num = tag_decode(self.tag)
2323 self.tag_constructed = tag_encode(
2325 form=TagFormConstructed,
2329 def _bits2octets(self, bits):
2330 if len(self.specs) > 0:
2331 bits = bits.rstrip("0")
2333 bits += "0" * ((8 - (bit_len % 8)) % 8)
2334 octets = bytearray(len(bits) // 8)
2335 for i in six_xrange(len(octets)):
2336 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2337 return bit_len, bytes(octets)
2339 def _value_sanitize(self, value):
2340 if isinstance(value, (string_types, binary_type)):
2342 isinstance(value, string_types) and
2343 value.startswith("'")
2345 if value.endswith("'B"):
2347 if not frozenset(value) <= SET01:
2348 raise ValueError("B's coding contains unacceptable chars")
2349 return self._bits2octets(value)
2350 if value.endswith("'H"):
2354 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2356 if isinstance(value, binary_type):
2357 return (len(value) * 8, value)
2358 raise InvalidValueType((self.__class__, string_types, binary_type))
2359 if isinstance(value, tuple):
2362 isinstance(value[0], integer_types) and
2363 isinstance(value[1], binary_type)
2368 bit = self.specs.get(name)
2370 raise ObjUnknown("BitString value: %s" % name)
2373 return self._bits2octets("")
2374 bits = frozenset(bits)
2375 return self._bits2octets("".join(
2376 ("1" if bit in bits else "0")
2377 for bit in six_xrange(max(bits) + 1)
2379 if issubclass(value.__class__, BitString):
2381 raise InvalidValueType((self.__class__, binary_type, string_types))
2385 return self._value is not None
2388 obj = self.__class__(_specs=self.specs)
2390 if value is not None:
2391 value = (value[0], value[1])
2394 obj._expl = self._expl
2395 obj.default = self.default
2396 obj.optional = self.optional
2397 obj.offset = self.offset
2398 obj.llen = self.llen
2399 obj.vlen = self.vlen
2400 obj.expl_lenindef = self.expl_lenindef
2401 obj.lenindef = self.lenindef
2402 obj.ber_encoded = self.ber_encoded
2406 self._assert_ready()
2407 for i in six_xrange(self._value[0]):
2412 self._assert_ready()
2413 return self._value[0]
2415 def __bytes__(self):
2416 self._assert_ready()
2417 return self._value[1]
2419 def __eq__(self, their):
2420 if isinstance(their, bytes):
2421 return self._value[1] == their
2422 if not issubclass(their.__class__, BitString):
2425 self._value == their._value and
2426 self.tag == their.tag and
2427 self._expl == their._expl
2432 return [name for name, bit in iteritems(self.specs) if self[bit]]
2442 return self.__class__(
2444 impl=self.tag if impl is None else impl,
2445 expl=self._expl if expl is None else expl,
2446 default=self.default if default is None else default,
2447 optional=self.optional if optional is None else optional,
2451 def __getitem__(self, key):
2452 if isinstance(key, int):
2453 bit_len, octets = self._value
2457 byte2int(memoryview(octets)[key // 8:]) >>
2460 if isinstance(key, string_types):
2461 value = self.specs.get(key)
2463 raise ObjUnknown("BitString value: %s" % key)
2465 raise InvalidValueType((int, str))
2468 self._assert_ready()
2469 bit_len, octets = self._value
2472 len_encode(len(octets) + 1),
2473 int2byte((8 - bit_len % 8) % 8),
2477 def _decode_chunk(self, lv, offset, decode_path):
2479 l, llen, v = len_decode(lv)
2480 except DecodeError as err:
2481 raise err.__class__(
2483 klass=self.__class__,
2484 decode_path=decode_path,
2488 raise NotEnoughData(
2489 "encoded length is longer than data",
2490 klass=self.__class__,
2491 decode_path=decode_path,
2495 raise NotEnoughData(
2497 klass=self.__class__,
2498 decode_path=decode_path,
2501 pad_size = byte2int(v)
2502 if l == 1 and pad_size != 0:
2504 "invalid empty value",
2505 klass=self.__class__,
2506 decode_path=decode_path,
2512 klass=self.__class__,
2513 decode_path=decode_path,
2516 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2519 klass=self.__class__,
2520 decode_path=decode_path,
2523 v, tail = v[:l], v[l:]
2524 obj = self.__class__(
2525 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2528 default=self.default,
2529 optional=self.optional,
2531 _decoded=(offset, llen, l),
2535 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2537 t, tlen, lv = tag_strip(tlv)
2538 except DecodeError as err:
2539 raise err.__class__(
2541 klass=self.__class__,
2542 decode_path=decode_path,
2546 if tag_only: # pragma: no cover
2548 return self._decode_chunk(lv, offset, decode_path)
2549 if t == self.tag_constructed:
2550 if not ctx.get("bered", False):
2552 "unallowed BER constructed encoding",
2553 klass=self.__class__,
2554 decode_path=decode_path,
2557 if tag_only: # pragma: no cover
2561 l, llen, v = len_decode(lv)
2562 except LenIndefForm:
2563 llen, l, v = 1, 0, lv[1:]
2565 except DecodeError as err:
2566 raise err.__class__(
2568 klass=self.__class__,
2569 decode_path=decode_path,
2573 raise NotEnoughData(
2574 "encoded length is longer than data",
2575 klass=self.__class__,
2576 decode_path=decode_path,
2579 if not lenindef and l == 0:
2580 raise NotEnoughData(
2582 klass=self.__class__,
2583 decode_path=decode_path,
2587 sub_offset = offset + tlen + llen
2591 if v[:EOC_LEN].tobytes() == EOC:
2598 "chunk out of bounds",
2599 klass=self.__class__,
2600 decode_path=decode_path + (str(len(chunks) - 1),),
2601 offset=chunks[-1].offset,
2603 sub_decode_path = decode_path + (str(len(chunks)),)
2605 chunk, v_tail = BitString().decode(
2608 decode_path=sub_decode_path,
2611 _ctx_immutable=False,
2615 "expected BitString encoded chunk",
2616 klass=self.__class__,
2617 decode_path=sub_decode_path,
2620 chunks.append(chunk)
2621 sub_offset += chunk.tlvlen
2622 vlen += chunk.tlvlen
2624 if len(chunks) == 0:
2627 klass=self.__class__,
2628 decode_path=decode_path,
2633 for chunk_i, chunk in enumerate(chunks[:-1]):
2634 if chunk.bit_len % 8 != 0:
2636 "BitString chunk is not multiple of 8 bits",
2637 klass=self.__class__,
2638 decode_path=decode_path + (str(chunk_i),),
2639 offset=chunk.offset,
2641 values.append(bytes(chunk))
2642 bit_len += chunk.bit_len
2643 chunk_last = chunks[-1]
2644 values.append(bytes(chunk_last))
2645 bit_len += chunk_last.bit_len
2646 obj = self.__class__(
2647 value=(bit_len, b"".join(values)),
2650 default=self.default,
2651 optional=self.optional,
2653 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2655 obj.lenindef = lenindef
2656 obj.ber_encoded = True
2657 return obj, (v[EOC_LEN:] if lenindef else v)
2659 klass=self.__class__,
2660 decode_path=decode_path,
2665 return pp_console_row(next(self.pps()))
2667 def pps(self, decode_path=()):
2671 bit_len, blob = self._value
2672 value = "%d bits" % bit_len
2673 if len(self.specs) > 0:
2674 blob = tuple(self.named)
2677 asn1_type_name=self.asn1_type_name,
2678 obj_name=self.__class__.__name__,
2679 decode_path=decode_path,
2682 optional=self.optional,
2683 default=self == self.default,
2684 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2685 expl=None if self._expl is None else tag_decode(self._expl),
2690 expl_offset=self.expl_offset if self.expled else None,
2691 expl_tlen=self.expl_tlen if self.expled else None,
2692 expl_llen=self.expl_llen if self.expled else None,
2693 expl_vlen=self.expl_vlen if self.expled else None,
2694 expl_lenindef=self.expl_lenindef,
2695 lenindef=self.lenindef,
2696 ber_encoded=self.ber_encoded,
2699 defined_by, defined = self.defined or (None, None)
2700 if defined_by is not None:
2702 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2704 for pp in self.pps_lenindef(decode_path):
2708 class OctetString(Obj):
2709 """``OCTET STRING`` binary string type
2711 >>> s = OctetString(b"hello world")
2712 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2713 >>> s == OctetString(b"hello world")
2718 >>> OctetString(b"hello", bounds=(4, 4))
2719 Traceback (most recent call last):
2720 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2721 >>> OctetString(b"hell", bounds=(4, 4))
2722 OCTET STRING 4 bytes 68656c6c
2726 Pay attention that OCTET STRING can be encoded both in primitive
2727 and constructed forms. Decoder always checks constructed form tag
2728 additionally to specified primitive one. If BER decoding is
2729 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2730 of DER restrictions.
2732 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2733 tag_default = tag_encode(4)
2734 asn1_type_name = "OCTET STRING"
2747 :param value: set the value. Either binary type, or
2748 :py:class:`pyderasn.OctetString` object
2749 :param bounds: set ``(MIN, MAX)`` value size constraint.
2750 (-inf, +inf) by default
2751 :param bytes impl: override default tag with ``IMPLICIT`` one
2752 :param bytes expl: override default tag with ``EXPLICIT`` one
2753 :param default: set default value. Type same as in ``value``
2754 :param bool optional: is object ``OPTIONAL`` in sequence
2756 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2758 self._bound_min, self._bound_max = getattr(
2762 ) if bounds is None else bounds
2763 if value is not None:
2764 self._value = self._value_sanitize(value)
2765 if default is not None:
2766 default = self._value_sanitize(default)
2767 self.default = self.__class__(
2772 if self._value is None:
2773 self._value = default
2775 tag_klass, _, tag_num = tag_decode(self.tag)
2776 self.tag_constructed = tag_encode(
2778 form=TagFormConstructed,
2782 def _value_sanitize(self, value):
2783 if isinstance(value, binary_type):
2785 elif issubclass(value.__class__, OctetString):
2786 value = value._value
2788 raise InvalidValueType((self.__class__, bytes))
2789 if not self._bound_min <= len(value) <= self._bound_max:
2790 raise BoundsError(self._bound_min, len(value), self._bound_max)
2795 return self._value is not None
2798 obj = self.__class__()
2799 obj._value = self._value
2800 obj._bound_min = self._bound_min
2801 obj._bound_max = self._bound_max
2803 obj._expl = self._expl
2804 obj.default = self.default
2805 obj.optional = self.optional
2806 obj.offset = self.offset
2807 obj.llen = self.llen
2808 obj.vlen = self.vlen
2809 obj.expl_lenindef = self.expl_lenindef
2810 obj.lenindef = self.lenindef
2811 obj.ber_encoded = self.ber_encoded
2814 def __bytes__(self):
2815 self._assert_ready()
2818 def __eq__(self, their):
2819 if isinstance(their, binary_type):
2820 return self._value == their
2821 if not issubclass(their.__class__, OctetString):
2824 self._value == their._value and
2825 self.tag == their.tag and
2826 self._expl == their._expl
2829 def __lt__(self, their):
2830 return self._value < their._value
2841 return self.__class__(
2844 (self._bound_min, self._bound_max)
2845 if bounds is None else bounds
2847 impl=self.tag if impl is None else impl,
2848 expl=self._expl if expl is None else expl,
2849 default=self.default if default is None else default,
2850 optional=self.optional if optional is None else optional,
2854 self._assert_ready()
2857 len_encode(len(self._value)),
2861 def _decode_chunk(self, lv, offset, decode_path):
2863 l, llen, v = len_decode(lv)
2864 except DecodeError as err:
2865 raise err.__class__(
2867 klass=self.__class__,
2868 decode_path=decode_path,
2872 raise NotEnoughData(
2873 "encoded length is longer than data",
2874 klass=self.__class__,
2875 decode_path=decode_path,
2878 v, tail = v[:l], v[l:]
2880 obj = self.__class__(
2882 bounds=(self._bound_min, self._bound_max),
2885 default=self.default,
2886 optional=self.optional,
2887 _decoded=(offset, llen, l),
2889 except DecodeError as err:
2892 klass=self.__class__,
2893 decode_path=decode_path,
2896 except BoundsError as err:
2899 klass=self.__class__,
2900 decode_path=decode_path,
2905 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2907 t, tlen, lv = tag_strip(tlv)
2908 except DecodeError as err:
2909 raise err.__class__(
2911 klass=self.__class__,
2912 decode_path=decode_path,
2918 return self._decode_chunk(lv, offset, decode_path)
2919 if t == self.tag_constructed:
2920 if not ctx.get("bered", False):
2922 "unallowed BER constructed encoding",
2923 klass=self.__class__,
2924 decode_path=decode_path,
2931 l, llen, v = len_decode(lv)
2932 except LenIndefForm:
2933 llen, l, v = 1, 0, lv[1:]
2935 except DecodeError as err:
2936 raise err.__class__(
2938 klass=self.__class__,
2939 decode_path=decode_path,
2943 raise NotEnoughData(
2944 "encoded length is longer than data",
2945 klass=self.__class__,
2946 decode_path=decode_path,
2950 sub_offset = offset + tlen + llen
2954 if v[:EOC_LEN].tobytes() == EOC:
2961 "chunk out of bounds",
2962 klass=self.__class__,
2963 decode_path=decode_path + (str(len(chunks) - 1),),
2964 offset=chunks[-1].offset,
2966 sub_decode_path = decode_path + (str(len(chunks)),)
2968 chunk, v_tail = OctetString().decode(
2971 decode_path=sub_decode_path,
2974 _ctx_immutable=False,
2978 "expected OctetString encoded chunk",
2979 klass=self.__class__,
2980 decode_path=sub_decode_path,
2983 chunks.append(chunk)
2984 sub_offset += chunk.tlvlen
2985 vlen += chunk.tlvlen
2988 obj = self.__class__(
2989 value=b"".join(bytes(chunk) for chunk in chunks),
2990 bounds=(self._bound_min, self._bound_max),
2993 default=self.default,
2994 optional=self.optional,
2995 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2997 except DecodeError as err:
3000 klass=self.__class__,
3001 decode_path=decode_path,
3004 except BoundsError as err:
3007 klass=self.__class__,
3008 decode_path=decode_path,
3011 obj.lenindef = lenindef
3012 obj.ber_encoded = True
3013 return obj, (v[EOC_LEN:] if lenindef else v)
3015 klass=self.__class__,
3016 decode_path=decode_path,
3021 return pp_console_row(next(self.pps()))
3023 def pps(self, decode_path=()):
3026 asn1_type_name=self.asn1_type_name,
3027 obj_name=self.__class__.__name__,
3028 decode_path=decode_path,
3029 value=("%d bytes" % len(self._value)) if self.ready else None,
3030 blob=self._value if self.ready else None,
3031 optional=self.optional,
3032 default=self == self.default,
3033 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3034 expl=None if self._expl is None else tag_decode(self._expl),
3039 expl_offset=self.expl_offset if self.expled else None,
3040 expl_tlen=self.expl_tlen if self.expled else None,
3041 expl_llen=self.expl_llen if self.expled else None,
3042 expl_vlen=self.expl_vlen if self.expled else None,
3043 expl_lenindef=self.expl_lenindef,
3044 lenindef=self.lenindef,
3045 ber_encoded=self.ber_encoded,
3048 defined_by, defined = self.defined or (None, None)
3049 if defined_by is not None:
3051 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3053 for pp in self.pps_lenindef(decode_path):
3058 """``NULL`` null object
3066 tag_default = tag_encode(5)
3067 asn1_type_name = "NULL"
3071 value=None, # unused, but Sequence passes it
3078 :param bytes impl: override default tag with ``IMPLICIT`` one
3079 :param bytes expl: override default tag with ``EXPLICIT`` one
3080 :param bool optional: is object ``OPTIONAL`` in sequence
3082 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3090 obj = self.__class__()
3092 obj._expl = self._expl
3093 obj.default = self.default
3094 obj.optional = self.optional
3095 obj.offset = self.offset
3096 obj.llen = self.llen
3097 obj.vlen = self.vlen
3098 obj.expl_lenindef = self.expl_lenindef
3099 obj.lenindef = self.lenindef
3100 obj.ber_encoded = self.ber_encoded
3103 def __eq__(self, their):
3104 if not issubclass(their.__class__, Null):
3107 self.tag == their.tag and
3108 self._expl == their._expl
3118 return self.__class__(
3119 impl=self.tag if impl is None else impl,
3120 expl=self._expl if expl is None else expl,
3121 optional=self.optional if optional is None else optional,
3125 return self.tag + len_encode(0)
3127 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3129 t, _, lv = tag_strip(tlv)
3130 except DecodeError as err:
3131 raise err.__class__(
3133 klass=self.__class__,
3134 decode_path=decode_path,
3139 klass=self.__class__,
3140 decode_path=decode_path,
3143 if tag_only: # pragma: no cover
3146 l, _, v = len_decode(lv)
3147 except DecodeError as err:
3148 raise err.__class__(
3150 klass=self.__class__,
3151 decode_path=decode_path,
3155 raise InvalidLength(
3156 "Null must have zero length",
3157 klass=self.__class__,
3158 decode_path=decode_path,
3161 obj = self.__class__(
3164 optional=self.optional,
3165 _decoded=(offset, 1, 0),
3170 return pp_console_row(next(self.pps()))
3172 def pps(self, decode_path=()):
3175 asn1_type_name=self.asn1_type_name,
3176 obj_name=self.__class__.__name__,
3177 decode_path=decode_path,
3178 optional=self.optional,
3179 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3180 expl=None if self._expl is None else tag_decode(self._expl),
3185 expl_offset=self.expl_offset if self.expled else None,
3186 expl_tlen=self.expl_tlen if self.expled else None,
3187 expl_llen=self.expl_llen if self.expled else None,
3188 expl_vlen=self.expl_vlen if self.expled else None,
3189 expl_lenindef=self.expl_lenindef,
3192 for pp in self.pps_lenindef(decode_path):
3196 class ObjectIdentifier(Obj):
3197 """``OBJECT IDENTIFIER`` OID type
3199 >>> oid = ObjectIdentifier((1, 2, 3))
3200 OBJECT IDENTIFIER 1.2.3
3201 >>> oid == ObjectIdentifier("1.2.3")
3207 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3208 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3210 >>> str(ObjectIdentifier((3, 1)))
3211 Traceback (most recent call last):
3212 pyderasn.InvalidOID: unacceptable first arc value
3214 __slots__ = ("defines",)
3215 tag_default = tag_encode(6)
3216 asn1_type_name = "OBJECT IDENTIFIER"
3229 :param value: set the value. Either tuples of integers,
3230 string of "."-concatenated integers, or
3231 :py:class:`pyderasn.ObjectIdentifier` object
3232 :param defines: sequence of tuples. Each tuple has two elements.
3233 First one is relative to current one decode
3234 path, aiming to the field defined by that OID.
3235 Read about relative path in
3236 :py:func:`pyderasn.abs_decode_path`. Second
3237 tuple element is ``{OID: pyderasn.Obj()}``
3238 dictionary, mapping between current OID value
3239 and structure applied to defined field.
3240 :ref:`Read about DEFINED BY <definedby>`
3241 :param bytes impl: override default tag with ``IMPLICIT`` one
3242 :param bytes expl: override default tag with ``EXPLICIT`` one
3243 :param default: set default value. Type same as in ``value``
3244 :param bool optional: is object ``OPTIONAL`` in sequence
3246 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3248 if value is not None:
3249 self._value = self._value_sanitize(value)
3250 if default is not None:
3251 default = self._value_sanitize(default)
3252 self.default = self.__class__(
3257 if self._value is None:
3258 self._value = default
3259 self.defines = defines
3261 def __add__(self, their):
3262 if isinstance(their, self.__class__):
3263 return self.__class__(self._value + their._value)
3264 if isinstance(their, tuple):
3265 return self.__class__(self._value + their)
3266 raise InvalidValueType((self.__class__, tuple))
3268 def _value_sanitize(self, value):
3269 if issubclass(value.__class__, ObjectIdentifier):
3271 if isinstance(value, string_types):
3273 value = tuple(int(arc) for arc in value.split("."))
3275 raise InvalidOID("unacceptable arcs values")
3276 if isinstance(value, tuple):
3278 raise InvalidOID("less than 2 arcs")
3279 first_arc = value[0]
3280 if first_arc in (0, 1):
3281 if not (0 <= value[1] <= 39):
3282 raise InvalidOID("second arc is too wide")
3283 elif first_arc == 2:
3286 raise InvalidOID("unacceptable first arc value")
3288 raise InvalidValueType((self.__class__, str, tuple))
3292 return self._value is not None
3295 obj = self.__class__()
3296 obj._value = self._value
3297 obj.defines = self.defines
3299 obj._expl = self._expl
3300 obj.default = self.default
3301 obj.optional = self.optional
3302 obj.offset = self.offset
3303 obj.llen = self.llen
3304 obj.vlen = self.vlen
3305 obj.expl_lenindef = self.expl_lenindef
3306 obj.lenindef = self.lenindef
3307 obj.ber_encoded = self.ber_encoded
3311 self._assert_ready()
3312 return iter(self._value)
3315 return ".".join(str(arc) for arc in self._value or ())
3318 self._assert_ready()
3321 bytes(self._expl or b"") +
3322 str(self._value).encode("ascii"),
3325 def __eq__(self, their):
3326 if isinstance(their, tuple):
3327 return self._value == their
3328 if not issubclass(their.__class__, ObjectIdentifier):
3331 self.tag == their.tag and
3332 self._expl == their._expl and
3333 self._value == their._value
3336 def __lt__(self, their):
3337 return self._value < their._value
3348 return self.__class__(
3350 defines=self.defines if defines is None else defines,
3351 impl=self.tag if impl is None else impl,
3352 expl=self._expl if expl is None else expl,
3353 default=self.default if default is None else default,
3354 optional=self.optional if optional is None else optional,
3358 self._assert_ready()
3360 first_value = value[1]
3361 first_arc = value[0]
3364 elif first_arc == 1:
3366 elif first_arc == 2:
3368 else: # pragma: no cover
3369 raise RuntimeError("invalid arc is stored")
3370 octets = [zero_ended_encode(first_value)]
3371 for arc in value[2:]:
3372 octets.append(zero_ended_encode(arc))
3373 v = b"".join(octets)
3374 return b"".join((self.tag, len_encode(len(v)), v))
3376 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3378 t, _, lv = tag_strip(tlv)
3379 except DecodeError as err:
3380 raise err.__class__(
3382 klass=self.__class__,
3383 decode_path=decode_path,
3388 klass=self.__class__,
3389 decode_path=decode_path,
3392 if tag_only: # pragma: no cover
3395 l, llen, v = len_decode(lv)
3396 except DecodeError as err:
3397 raise err.__class__(
3399 klass=self.__class__,
3400 decode_path=decode_path,
3404 raise NotEnoughData(
3405 "encoded length is longer than data",
3406 klass=self.__class__,
3407 decode_path=decode_path,
3411 raise NotEnoughData(
3413 klass=self.__class__,
3414 decode_path=decode_path,
3417 v, tail = v[:l], v[l:]
3424 octet = indexbytes(v, i)
3425 if i == 0 and octet == 0x80:
3426 if ctx.get("bered", False):
3429 raise DecodeError("non normalized arc encoding")
3430 arc = (arc << 7) | (octet & 0x7F)
3431 if octet & 0x80 == 0:
3439 klass=self.__class__,
3440 decode_path=decode_path,
3444 second_arc = arcs[0]
3445 if 0 <= second_arc <= 39:
3447 elif 40 <= second_arc <= 79:
3453 obj = self.__class__(
3454 value=tuple([first_arc, second_arc] + arcs[1:]),
3457 default=self.default,
3458 optional=self.optional,
3459 _decoded=(offset, llen, l),
3462 obj.ber_encoded = True
3466 return pp_console_row(next(self.pps()))
3468 def pps(self, decode_path=()):
3471 asn1_type_name=self.asn1_type_name,
3472 obj_name=self.__class__.__name__,
3473 decode_path=decode_path,
3474 value=str(self) if self.ready else None,
3475 optional=self.optional,
3476 default=self == self.default,
3477 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3478 expl=None if self._expl is None else tag_decode(self._expl),
3483 expl_offset=self.expl_offset if self.expled else None,
3484 expl_tlen=self.expl_tlen if self.expled else None,
3485 expl_llen=self.expl_llen if self.expled else None,
3486 expl_vlen=self.expl_vlen if self.expled else None,
3487 expl_lenindef=self.expl_lenindef,
3488 ber_encoded=self.ber_encoded,
3491 for pp in self.pps_lenindef(decode_path):
3495 class Enumerated(Integer):
3496 """``ENUMERATED`` integer type
3498 This type is identical to :py:class:`pyderasn.Integer`, but requires
3499 schema to be specified and does not accept values missing from it.
3502 tag_default = tag_encode(10)
3503 asn1_type_name = "ENUMERATED"
3514 bounds=None, # dummy argument, workability for Integer.decode
3516 super(Enumerated, self).__init__(
3517 value, bounds, impl, expl, default, optional, _specs, _decoded,
3519 if len(self.specs) == 0:
3520 raise ValueError("schema must be specified")
3522 def _value_sanitize(self, value):
3523 if isinstance(value, self.__class__):
3524 value = value._value
3525 elif isinstance(value, integer_types):
3526 for _value in itervalues(self.specs):
3531 "unknown integer value: %s" % value,
3532 klass=self.__class__,
3534 elif isinstance(value, string_types):
3535 value = self.specs.get(value)
3537 raise ObjUnknown("integer value: %s" % value)
3539 raise InvalidValueType((self.__class__, int, str))
3543 obj = self.__class__(_specs=self.specs)
3544 obj._value = self._value
3545 obj._bound_min = self._bound_min
3546 obj._bound_max = self._bound_max
3548 obj._expl = self._expl
3549 obj.default = self.default
3550 obj.optional = self.optional
3551 obj.offset = self.offset
3552 obj.llen = self.llen
3553 obj.vlen = self.vlen
3554 obj.expl_lenindef = self.expl_lenindef
3555 obj.lenindef = self.lenindef
3556 obj.ber_encoded = self.ber_encoded
3568 return self.__class__(
3570 impl=self.tag if impl is None else impl,
3571 expl=self._expl if expl is None else expl,
3572 default=self.default if default is None else default,
3573 optional=self.optional if optional is None else optional,
3578 def escape_control_unicode(c):
3579 if unicat(c).startswith("C"):
3580 c = repr(c).lstrip("u").strip("'")
3584 class CommonString(OctetString):
3585 """Common class for all strings
3587 Everything resembles :py:class:`pyderasn.OctetString`, except
3588 ability to deal with unicode text strings.
3590 >>> hexenc("привет мир".encode("utf-8"))
3591 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3592 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3594 >>> s = UTF8String("привет мир")
3595 UTF8String UTF8String привет мир
3597 'привет мир'
3598 >>> hexenc(bytes(s))
3599 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3601 >>> PrintableString("привет мир")
3602 Traceback (most recent call last):
3603 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3605 >>> BMPString("ада", bounds=(2, 2))
3606 Traceback (most recent call last):
3607 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3608 >>> s = BMPString("ад", bounds=(2, 2))
3611 >>> hexenc(bytes(s))
3619 * - :py:class:`pyderasn.UTF8String`
3621 * - :py:class:`pyderasn.NumericString`
3623 * - :py:class:`pyderasn.PrintableString`
3625 * - :py:class:`pyderasn.TeletexString`
3627 * - :py:class:`pyderasn.T61String`
3629 * - :py:class:`pyderasn.VideotexString`
3631 * - :py:class:`pyderasn.IA5String`
3633 * - :py:class:`pyderasn.GraphicString`
3635 * - :py:class:`pyderasn.VisibleString`
3637 * - :py:class:`pyderasn.ISO646String`
3639 * - :py:class:`pyderasn.GeneralString`
3641 * - :py:class:`pyderasn.UniversalString`
3643 * - :py:class:`pyderasn.BMPString`
3648 def _value_sanitize(self, value):
3650 value_decoded = None
3651 if isinstance(value, self.__class__):
3652 value_raw = value._value
3653 elif isinstance(value, text_type):
3654 value_decoded = value
3655 elif isinstance(value, binary_type):
3658 raise InvalidValueType((self.__class__, text_type, binary_type))
3661 value_decoded.encode(self.encoding)
3662 if value_raw is None else value_raw
3665 value_raw.decode(self.encoding)
3666 if value_decoded is None else value_decoded
3668 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3669 raise DecodeError(str(err))
3670 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3678 def __eq__(self, their):
3679 if isinstance(their, binary_type):
3680 return self._value == their
3681 if isinstance(their, text_type):
3682 return self._value == their.encode(self.encoding)
3683 if not isinstance(their, self.__class__):
3686 self._value == their._value and
3687 self.tag == their.tag and
3688 self._expl == their._expl
3691 def __unicode__(self):
3693 return self._value.decode(self.encoding)
3694 return text_type(self._value)
3697 return pp_console_row(next(self.pps(no_unicode=PY2)))
3699 def pps(self, decode_path=(), no_unicode=False):
3703 hexenc(bytes(self)) if no_unicode else
3704 "".join(escape_control_unicode(c) for c in self.__unicode__())
3708 asn1_type_name=self.asn1_type_name,
3709 obj_name=self.__class__.__name__,
3710 decode_path=decode_path,
3712 optional=self.optional,
3713 default=self == self.default,
3714 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3715 expl=None if self._expl is None else tag_decode(self._expl),
3720 expl_offset=self.expl_offset if self.expled else None,
3721 expl_tlen=self.expl_tlen if self.expled else None,
3722 expl_llen=self.expl_llen if self.expled else None,
3723 expl_vlen=self.expl_vlen if self.expled else None,
3724 expl_lenindef=self.expl_lenindef,
3725 ber_encoded=self.ber_encoded,
3728 for pp in self.pps_lenindef(decode_path):
3732 class UTF8String(CommonString):
3734 tag_default = tag_encode(12)
3736 asn1_type_name = "UTF8String"
3739 class AllowableCharsMixin(object):
3741 def allowable_chars(self):
3743 return self._allowable_chars
3744 return frozenset(six_unichr(c) for c in self._allowable_chars)
3747 class NumericString(AllowableCharsMixin, CommonString):
3750 Its value is properly sanitized: only ASCII digits with spaces can
3753 >>> NumericString().allowable_chars
3754 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3757 tag_default = tag_encode(18)
3759 asn1_type_name = "NumericString"
3760 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3762 def _value_sanitize(self, value):
3763 value = super(NumericString, self)._value_sanitize(value)
3764 if not frozenset(value) <= self._allowable_chars:
3765 raise DecodeError("non-numeric value")
3769 class PrintableString(AllowableCharsMixin, CommonString):
3772 Its value is properly sanitized: see X.680 41.4 table 10.
3774 >>> PrintableString().allowable_chars
3775 frozenset([' ', "'", ..., 'z'])
3778 tag_default = tag_encode(19)
3780 asn1_type_name = "PrintableString"
3781 _allowable_chars = frozenset(
3782 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
3784 _asterisk = frozenset("*".encode("ascii"))
3785 _ampersand = frozenset("&".encode("ascii"))
3796 allow_asterisk=False,
3797 allow_ampersand=False,
3800 :param allow_asterisk: allow asterisk character
3801 :param allow_ampersand: allow ampersand character
3804 self._allowable_chars |= self._asterisk
3806 self._allowable_chars |= self._ampersand
3807 super(PrintableString, self).__init__(
3808 value, bounds, impl, expl, default, optional, _decoded,
3811 def _value_sanitize(self, value):
3812 value = super(PrintableString, self)._value_sanitize(value)
3813 if not frozenset(value) <= self._allowable_chars:
3814 raise DecodeError("non-printable value")
3818 obj = super(PrintableString, self).copy()
3819 obj._allowable_chars = self._allowable_chars
3831 return self.__class__(
3834 (self._bound_min, self._bound_max)
3835 if bounds is None else bounds
3837 impl=self.tag if impl is None else impl,
3838 expl=self._expl if expl is None else expl,
3839 default=self.default if default is None else default,
3840 optional=self.optional if optional is None else optional,
3841 allow_asterisk=self._asterisk <= self._allowable_chars,
3842 allow_ampersand=self._ampersand <= self._allowable_chars,
3846 class TeletexString(CommonString):
3848 tag_default = tag_encode(20)
3850 asn1_type_name = "TeletexString"
3853 class T61String(TeletexString):
3855 asn1_type_name = "T61String"
3858 class VideotexString(CommonString):
3860 tag_default = tag_encode(21)
3861 encoding = "iso-8859-1"
3862 asn1_type_name = "VideotexString"
3865 class IA5String(CommonString):
3867 tag_default = tag_encode(22)
3869 asn1_type_name = "IA5"
3872 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
3873 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
3874 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
3877 class UTCTime(CommonString):
3878 """``UTCTime`` datetime type
3880 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3881 UTCTime UTCTime 2017-09-30T22:07:50
3887 datetime.datetime(2017, 9, 30, 22, 7, 50)
3888 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
3889 datetime.datetime(1957, 9, 30, 22, 7, 50)
3893 BER encoding is unsupported.
3896 tag_default = tag_encode(23)
3898 asn1_type_name = "UTCTime"
3908 bounds=None, # dummy argument, workability for OctetString.decode
3911 :param value: set the value. Either datetime type, or
3912 :py:class:`pyderasn.UTCTime` object
3913 :param bytes impl: override default tag with ``IMPLICIT`` one
3914 :param bytes expl: override default tag with ``EXPLICIT`` one
3915 :param default: set default value. Type same as in ``value``
3916 :param bool optional: is object ``OPTIONAL`` in sequence
3918 super(UTCTime, self).__init__(
3919 None, None, impl, expl, default, optional, _decoded,
3922 if value is not None:
3923 self._value = self._value_sanitize(value)
3924 if default is not None:
3925 default = self._value_sanitize(default)
3926 self.default = self.__class__(
3931 if self._value is None:
3932 self._value = default
3934 def _strptime(self, value):
3935 # datetime.strptime's format: %y%m%d%H%M%SZ
3936 if len(value) != LEN_YYMMDDHHMMSSZ:
3937 raise ValueError("invalid UTCTime length")
3938 if value[-1] != "Z":
3939 raise ValueError("non UTC timezone")
3941 2000 + int(value[:2]), # %y
3942 int(value[2:4]), # %m
3943 int(value[4:6]), # %d
3944 int(value[6:8]), # %H
3945 int(value[8:10]), # %M
3946 int(value[10:12]), # %S
3949 def _value_sanitize(self, value):
3950 if isinstance(value, binary_type):
3952 value_decoded = value.decode("ascii")
3953 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3954 raise DecodeError("invalid UTCTime encoding: %r" % err)
3956 self._strptime(value_decoded)
3957 except (TypeError, ValueError) as err:
3958 raise DecodeError("invalid UTCTime format: %r" % err)
3960 if isinstance(value, self.__class__):
3962 if isinstance(value, datetime):
3963 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
3964 raise InvalidValueType((self.__class__, datetime))
3966 def __eq__(self, their):
3967 if isinstance(their, binary_type):
3968 return self._value == their
3969 if isinstance(their, datetime):
3970 return self.todatetime() == their
3971 if not isinstance(their, self.__class__):
3974 self._value == their._value and
3975 self.tag == their.tag and
3976 self._expl == their._expl
3979 def todatetime(self):
3980 """Convert to datetime
3984 Pay attention that UTCTime can not hold full year, so all years
3985 having < 50 years are treated as 20xx, 19xx otherwise, according
3986 to X.509 recomendation.
3988 value = self._strptime(self._value.decode("ascii"))
3989 year = value.year % 100
3991 year=(2000 + year) if year < 50 else (1900 + year),
3995 minute=value.minute,
3996 second=value.second,
4000 return pp_console_row(next(self.pps()))
4002 def pps(self, decode_path=()):
4005 asn1_type_name=self.asn1_type_name,
4006 obj_name=self.__class__.__name__,
4007 decode_path=decode_path,
4008 value=self.todatetime().isoformat() if self.ready else None,
4009 optional=self.optional,
4010 default=self == self.default,
4011 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4012 expl=None if self._expl is None else tag_decode(self._expl),
4017 expl_offset=self.expl_offset if self.expled else None,
4018 expl_tlen=self.expl_tlen if self.expled else None,
4019 expl_llen=self.expl_llen if self.expled else None,
4020 expl_vlen=self.expl_vlen if self.expled else None,
4021 expl_lenindef=self.expl_lenindef,
4022 ber_encoded=self.ber_encoded,
4025 for pp in self.pps_lenindef(decode_path):
4029 class GeneralizedTime(UTCTime):
4030 """``GeneralizedTime`` datetime type
4032 This type is similar to :py:class:`pyderasn.UTCTime`.
4034 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4035 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4037 '20170930220750.000123Z'
4038 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4039 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4043 BER encoding is unsupported.
4047 Only microsecond fractions are supported.
4048 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4049 higher precision values.
4052 tag_default = tag_encode(24)
4053 asn1_type_name = "GeneralizedTime"
4055 def _strptime(self, value):
4057 if l == LEN_YYYYMMDDHHMMSSZ:
4058 # datetime.strptime's format: %y%m%d%H%M%SZ
4059 if value[-1] != "Z":
4060 raise ValueError("non UTC timezone")
4062 int(value[:4]), # %Y
4063 int(value[4:6]), # %m
4064 int(value[6:8]), # %d
4065 int(value[8:10]), # %H
4066 int(value[10:12]), # %M
4067 int(value[12:14]), # %S
4069 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4070 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4071 if value[-1] != "Z":
4072 raise ValueError("non UTC timezone")
4073 if value[14] != ".":
4074 raise ValueError("no fractions separator")
4077 raise ValueError("trailing zero")
4080 raise ValueError("only microsecond fractions are supported")
4081 us = int(us + ("0" * (6 - us_len)))
4083 int(value[:4]), # %Y
4084 int(value[4:6]), # %m
4085 int(value[6:8]), # %d
4086 int(value[8:10]), # %H
4087 int(value[10:12]), # %M
4088 int(value[12:14]), # %S
4092 raise ValueError("invalid GeneralizedTime length")
4094 def _value_sanitize(self, value):
4095 if isinstance(value, binary_type):
4097 value_decoded = value.decode("ascii")
4098 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4099 raise DecodeError("invalid GeneralizedTime encoding: %r" % err)
4101 self._strptime(value_decoded)
4102 except (TypeError, ValueError) as err:
4104 "invalid GeneralizedTime format: %r" % err,
4105 klass=self.__class__,
4108 if isinstance(value, self.__class__):
4110 if isinstance(value, datetime):
4111 encoded = value.strftime("%Y%m%d%H%M%S")
4112 if value.microsecond > 0:
4113 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
4114 return (encoded + "Z").encode("ascii")
4115 raise InvalidValueType((self.__class__, datetime))
4117 def todatetime(self):
4118 return self._strptime(self._value.decode("ascii"))
4121 class GraphicString(CommonString):
4123 tag_default = tag_encode(25)
4124 encoding = "iso-8859-1"
4125 asn1_type_name = "GraphicString"
4128 class VisibleString(CommonString):
4130 tag_default = tag_encode(26)
4132 asn1_type_name = "VisibleString"
4135 class ISO646String(VisibleString):
4137 asn1_type_name = "ISO646String"
4140 class GeneralString(CommonString):
4142 tag_default = tag_encode(27)
4143 encoding = "iso-8859-1"
4144 asn1_type_name = "GeneralString"
4147 class UniversalString(CommonString):
4149 tag_default = tag_encode(28)
4150 encoding = "utf-32-be"
4151 asn1_type_name = "UniversalString"
4154 class BMPString(CommonString):
4156 tag_default = tag_encode(30)
4157 encoding = "utf-16-be"
4158 asn1_type_name = "BMPString"
4162 """``CHOICE`` special type
4166 class GeneralName(Choice):
4168 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4169 ("dNSName", IA5String(impl=tag_ctxp(2))),
4172 >>> gn = GeneralName()
4174 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4175 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4176 >>> gn["dNSName"] = IA5String("bar.baz")
4177 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4178 >>> gn["rfc822Name"]
4181 [2] IA5String IA5 bar.baz
4184 >>> gn.value == gn["dNSName"]
4187 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4189 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4190 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4192 __slots__ = ("specs",)
4194 asn1_type_name = "CHOICE"
4207 :param value: set the value. Either ``(choice, value)`` tuple, or
4208 :py:class:`pyderasn.Choice` object
4209 :param bytes impl: can not be set, do **not** use it
4210 :param bytes expl: override default tag with ``EXPLICIT`` one
4211 :param default: set default value. Type same as in ``value``
4212 :param bool optional: is object ``OPTIONAL`` in sequence
4214 if impl is not None:
4215 raise ValueError("no implicit tag allowed for CHOICE")
4216 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4218 schema = getattr(self, "schema", ())
4219 if len(schema) == 0:
4220 raise ValueError("schema must be specified")
4222 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4225 if value is not None:
4226 self._value = self._value_sanitize(value)
4227 if default is not None:
4228 default_value = self._value_sanitize(default)
4229 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4230 default_obj.specs = self.specs
4231 default_obj._value = default_value
4232 self.default = default_obj
4234 self._value = default_obj.copy()._value
4236 def _value_sanitize(self, value):
4237 if isinstance(value, tuple) and len(value) == 2:
4239 spec = self.specs.get(choice)
4241 raise ObjUnknown(choice)
4242 if not isinstance(obj, spec.__class__):
4243 raise InvalidValueType((spec,))
4244 return (choice, spec(obj))
4245 if isinstance(value, self.__class__):
4247 raise InvalidValueType((self.__class__, tuple))
4251 return self._value is not None and self._value[1].ready
4255 return self.expl_lenindef or (
4256 (self._value is not None) and
4257 self._value[1].bered
4261 obj = self.__class__(schema=self.specs)
4262 obj._expl = self._expl
4263 obj.default = self.default
4264 obj.optional = self.optional
4265 obj.offset = self.offset
4266 obj.llen = self.llen
4267 obj.vlen = self.vlen
4268 obj.expl_lenindef = self.expl_lenindef
4269 obj.lenindef = self.lenindef
4270 obj.ber_encoded = self.ber_encoded
4272 if value is not None:
4273 obj._value = (value[0], value[1].copy())
4276 def __eq__(self, their):
4277 if isinstance(their, tuple) and len(their) == 2:
4278 return self._value == their
4279 if not isinstance(their, self.__class__):
4282 self.specs == their.specs and
4283 self._value == their._value
4293 return self.__class__(
4296 expl=self._expl if expl is None else expl,
4297 default=self.default if default is None else default,
4298 optional=self.optional if optional is None else optional,
4303 self._assert_ready()
4304 return self._value[0]
4308 self._assert_ready()
4309 return self._value[1]
4311 def __getitem__(self, key):
4312 if key not in self.specs:
4313 raise ObjUnknown(key)
4314 if self._value is None:
4316 choice, value = self._value
4321 def __setitem__(self, key, value):
4322 spec = self.specs.get(key)
4324 raise ObjUnknown(key)
4325 if not isinstance(value, spec.__class__):
4326 raise InvalidValueType((spec.__class__,))
4327 self._value = (key, spec(value))
4335 return self._value[1].decoded if self.ready else False
4338 self._assert_ready()
4339 return self._value[1].encode()
4341 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4342 for choice, spec in iteritems(self.specs):
4343 sub_decode_path = decode_path + (choice,)
4349 decode_path=sub_decode_path,
4352 _ctx_immutable=False,
4359 klass=self.__class__,
4360 decode_path=decode_path,
4363 if tag_only: # pragma: no cover
4365 value, tail = spec.decode(
4369 decode_path=sub_decode_path,
4371 _ctx_immutable=False,
4373 obj = self.__class__(
4376 default=self.default,
4377 optional=self.optional,
4378 _decoded=(offset, 0, value.fulllen),
4380 obj._value = (choice, value)
4384 value = pp_console_row(next(self.pps()))
4386 value = "%s[%r]" % (value, self.value)
4389 def pps(self, decode_path=()):
4392 asn1_type_name=self.asn1_type_name,
4393 obj_name=self.__class__.__name__,
4394 decode_path=decode_path,
4395 value=self.choice if self.ready else None,
4396 optional=self.optional,
4397 default=self == self.default,
4398 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4399 expl=None if self._expl is None else tag_decode(self._expl),
4404 expl_lenindef=self.expl_lenindef,
4408 yield self.value.pps(decode_path=decode_path + (self.choice,))
4409 for pp in self.pps_lenindef(decode_path):
4413 class PrimitiveTypes(Choice):
4414 """Predefined ``CHOICE`` for all generic primitive types
4416 It could be useful for general decoding of some unspecified values:
4418 >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
4419 OCTET STRING 3 bytes 666f6f
4420 >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
4424 schema = tuple((klass.__name__, klass()) for klass in (
4449 """``ANY`` special type
4451 >>> Any(Integer(-123))
4453 >>> a = Any(OctetString(b"hello world").encode())
4454 ANY 040b68656c6c6f20776f726c64
4455 >>> hexenc(bytes(a))
4456 b'0x040x0bhello world'
4458 __slots__ = ("defined",)
4459 tag_default = tag_encode(0)
4460 asn1_type_name = "ANY"
4470 :param value: set the value. Either any kind of pyderasn's
4471 **ready** object, or bytes. Pay attention that
4472 **no** validation is performed is raw binary value
4474 :param bytes expl: override default tag with ``EXPLICIT`` one
4475 :param bool optional: is object ``OPTIONAL`` in sequence
4477 super(Any, self).__init__(None, expl, None, optional, _decoded)
4478 self._value = None if value is None else self._value_sanitize(value)
4481 def _value_sanitize(self, value):
4482 if isinstance(value, binary_type):
4484 if isinstance(value, self.__class__):
4486 if isinstance(value, Obj):
4487 return value.encode()
4488 raise InvalidValueType((self.__class__, Obj, binary_type))
4492 return self._value is not None
4496 if self.expl_lenindef or self.lenindef:
4498 if self.defined is None:
4500 return self.defined[1].bered
4503 obj = self.__class__()
4504 obj._value = self._value
4506 obj._expl = self._expl
4507 obj.optional = self.optional
4508 obj.offset = self.offset
4509 obj.llen = self.llen
4510 obj.vlen = self.vlen
4511 obj.expl_lenindef = self.expl_lenindef
4512 obj.lenindef = self.lenindef
4513 obj.ber_encoded = self.ber_encoded
4516 def __eq__(self, their):
4517 if isinstance(their, binary_type):
4518 return self._value == their
4519 if issubclass(their.__class__, Any):
4520 return self._value == their._value
4529 return self.__class__(
4531 expl=self._expl if expl is None else expl,
4532 optional=self.optional if optional is None else optional,
4535 def __bytes__(self):
4536 self._assert_ready()
4544 self._assert_ready()
4547 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4549 t, tlen, lv = tag_strip(tlv)
4550 except DecodeError as err:
4551 raise err.__class__(
4553 klass=self.__class__,
4554 decode_path=decode_path,
4558 l, llen, v = len_decode(lv)
4559 except LenIndefForm as err:
4560 if not ctx.get("bered", False):
4561 raise err.__class__(
4563 klass=self.__class__,
4564 decode_path=decode_path,
4567 llen, vlen, v = 1, 0, lv[1:]
4568 sub_offset = offset + tlen + llen
4570 while v[:EOC_LEN].tobytes() != EOC:
4571 chunk, v = Any().decode(
4574 decode_path=decode_path + (str(chunk_i),),
4577 _ctx_immutable=False,
4579 vlen += chunk.tlvlen
4580 sub_offset += chunk.tlvlen
4582 tlvlen = tlen + llen + vlen + EOC_LEN
4583 obj = self.__class__(
4584 value=tlv[:tlvlen].tobytes(),
4586 optional=self.optional,
4587 _decoded=(offset, 0, tlvlen),
4590 obj.tag = t.tobytes()
4591 return obj, v[EOC_LEN:]
4592 except DecodeError as err:
4593 raise err.__class__(
4595 klass=self.__class__,
4596 decode_path=decode_path,
4600 raise NotEnoughData(
4601 "encoded length is longer than data",
4602 klass=self.__class__,
4603 decode_path=decode_path,
4606 tlvlen = tlen + llen + l
4607 v, tail = tlv[:tlvlen], v[l:]
4608 obj = self.__class__(
4611 optional=self.optional,
4612 _decoded=(offset, 0, tlvlen),
4614 obj.tag = t.tobytes()
4618 return pp_console_row(next(self.pps()))
4620 def pps(self, decode_path=()):
4623 asn1_type_name=self.asn1_type_name,
4624 obj_name=self.__class__.__name__,
4625 decode_path=decode_path,
4626 blob=self._value if self.ready else None,
4627 optional=self.optional,
4628 default=self == self.default,
4629 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4630 expl=None if self._expl is None else tag_decode(self._expl),
4635 expl_offset=self.expl_offset if self.expled else None,
4636 expl_tlen=self.expl_tlen if self.expled else None,
4637 expl_llen=self.expl_llen if self.expled else None,
4638 expl_vlen=self.expl_vlen if self.expled else None,
4639 expl_lenindef=self.expl_lenindef,
4640 lenindef=self.lenindef,
4643 defined_by, defined = self.defined or (None, None)
4644 if defined_by is not None:
4646 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4648 for pp in self.pps_lenindef(decode_path):
4652 ########################################################################
4653 # ASN.1 constructed types
4654 ########################################################################
4656 def get_def_by_path(defines_by_path, sub_decode_path):
4657 """Get define by decode path
4659 for path, define in defines_by_path:
4660 if len(path) != len(sub_decode_path):
4662 for p1, p2 in zip(path, sub_decode_path):
4663 if (p1 != any) and (p1 != p2):
4669 def abs_decode_path(decode_path, rel_path):
4670 """Create an absolute decode path from current and relative ones
4672 :param decode_path: current decode path, starting point. Tuple of strings
4673 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4674 If first tuple's element is "/", then treat it as
4675 an absolute path, ignoring ``decode_path`` as
4676 starting point. Also this tuple can contain ".."
4677 elements, stripping the leading element from
4680 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4681 ("foo", "bar", "baz", "whatever")
4682 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4684 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4687 if rel_path[0] == "/":
4689 if rel_path[0] == "..":
4690 return abs_decode_path(decode_path[:-1], rel_path[1:])
4691 return decode_path + rel_path
4694 class Sequence(Obj):
4695 """``SEQUENCE`` structure type
4697 You have to make specification of sequence::
4699 class Extension(Sequence):
4701 ("extnID", ObjectIdentifier()),
4702 ("critical", Boolean(default=False)),
4703 ("extnValue", OctetString()),
4706 Then, you can work with it as with dictionary.
4708 >>> ext = Extension()
4709 >>> Extension().specs
4711 ('extnID', OBJECT IDENTIFIER),
4712 ('critical', BOOLEAN False OPTIONAL DEFAULT),
4713 ('extnValue', OCTET STRING),
4715 >>> ext["extnID"] = "1.2.3"
4716 Traceback (most recent call last):
4717 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
4718 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
4720 You can determine if sequence is ready to be encoded:
4725 Traceback (most recent call last):
4726 pyderasn.ObjNotReady: object is not ready: extnValue
4727 >>> ext["extnValue"] = OctetString(b"foobar")
4731 Value you want to assign, must have the same **type** as in
4732 corresponding specification, but it can have different tags,
4733 optional/default attributes -- they will be taken from specification
4736 class TBSCertificate(Sequence):
4738 ("version", Version(expl=tag_ctxc(0), default="v1")),
4741 >>> tbs = TBSCertificate()
4742 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
4744 Assign ``None`` to remove value from sequence.
4746 You can set values in Sequence during its initialization:
4748 >>> AlgorithmIdentifier((
4749 ("algorithm", ObjectIdentifier("1.2.3")),
4750 ("parameters", Any(Null()))
4752 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
4754 You can determine if value exists/set in the sequence and take its value:
4756 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
4759 OBJECT IDENTIFIER 1.2.3
4761 But pay attention that if value has default, then it won't be (not
4762 in) in the sequence (because ``DEFAULT`` must not be encoded in
4763 DER), but you can read its value:
4765 >>> "critical" in ext, ext["critical"]
4766 (False, BOOLEAN False)
4767 >>> ext["critical"] = Boolean(True)
4768 >>> "critical" in ext, ext["critical"]
4769 (True, BOOLEAN True)
4771 All defaulted values are always optional.
4773 .. _allow_default_values_ctx:
4775 DER prohibits default value encoding and will raise an error if
4776 default value is unexpectedly met during decode.
4777 If :ref:`bered <bered_ctx>` context option is set, then no error
4778 will be raised, but ``bered`` attribute set. You can disable strict
4779 defaulted values existence validation by setting
4780 ``"allow_default_values": True`` :ref:`context <ctx>` option.
4782 Two sequences are equal if they have equal specification (schema),
4783 implicit/explicit tagging and the same values.
4785 __slots__ = ("specs",)
4786 tag_default = tag_encode(form=TagFormConstructed, num=16)
4787 asn1_type_name = "SEQUENCE"
4799 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
4801 schema = getattr(self, "schema", ())
4803 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4806 if value is not None:
4807 if issubclass(value.__class__, Sequence):
4808 self._value = value._value
4809 elif hasattr(value, "__iter__"):
4810 for seq_key, seq_value in value:
4811 self[seq_key] = seq_value
4813 raise InvalidValueType((Sequence,))
4814 if default is not None:
4815 if not issubclass(default.__class__, Sequence):
4816 raise InvalidValueType((Sequence,))
4817 default_value = default._value
4818 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4819 default_obj.specs = self.specs
4820 default_obj._value = default_value
4821 self.default = default_obj
4823 self._value = default_obj.copy()._value
4827 for name, spec in iteritems(self.specs):
4828 value = self._value.get(name)
4839 if self.expl_lenindef or self.lenindef or self.ber_encoded:
4841 return any(value.bered for value in itervalues(self._value))
4844 obj = self.__class__(schema=self.specs)
4846 obj._expl = self._expl
4847 obj.default = self.default
4848 obj.optional = self.optional
4849 obj.offset = self.offset
4850 obj.llen = self.llen
4851 obj.vlen = self.vlen
4852 obj.expl_lenindef = self.expl_lenindef
4853 obj.lenindef = self.lenindef
4854 obj.ber_encoded = self.ber_encoded
4855 obj._value = {k: v.copy() for k, v in iteritems(self._value)}
4858 def __eq__(self, their):
4859 if not isinstance(their, self.__class__):
4862 self.specs == their.specs and
4863 self.tag == their.tag and
4864 self._expl == their._expl and
4865 self._value == their._value
4876 return self.__class__(
4879 impl=self.tag if impl is None else impl,
4880 expl=self._expl if expl is None else expl,
4881 default=self.default if default is None else default,
4882 optional=self.optional if optional is None else optional,
4885 def __contains__(self, key):
4886 return key in self._value
4888 def __setitem__(self, key, value):
4889 spec = self.specs.get(key)
4891 raise ObjUnknown(key)
4893 self._value.pop(key, None)
4895 if not isinstance(value, spec.__class__):
4896 raise InvalidValueType((spec.__class__,))
4897 value = spec(value=value)
4898 if spec.default is not None and value == spec.default:
4899 self._value.pop(key, None)
4901 self._value[key] = value
4903 def __getitem__(self, key):
4904 value = self._value.get(key)
4905 if value is not None:
4907 spec = self.specs.get(key)
4909 raise ObjUnknown(key)
4910 if spec.default is not None:
4914 def _encoded_values(self):
4916 for name, spec in iteritems(self.specs):
4917 value = self._value.get(name)
4921 raise ObjNotReady(name)
4922 raws.append(value.encode())
4926 v = b"".join(self._encoded_values())
4927 return b"".join((self.tag, len_encode(len(v)), v))
4929 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4931 t, tlen, lv = tag_strip(tlv)
4932 except DecodeError as err:
4933 raise err.__class__(
4935 klass=self.__class__,
4936 decode_path=decode_path,
4941 klass=self.__class__,
4942 decode_path=decode_path,
4945 if tag_only: # pragma: no cover
4948 ctx_bered = ctx.get("bered", False)
4950 l, llen, v = len_decode(lv)
4951 except LenIndefForm as err:
4953 raise err.__class__(
4955 klass=self.__class__,
4956 decode_path=decode_path,
4959 l, llen, v = 0, 1, lv[1:]
4961 except DecodeError as err:
4962 raise err.__class__(
4964 klass=self.__class__,
4965 decode_path=decode_path,
4969 raise NotEnoughData(
4970 "encoded length is longer than data",
4971 klass=self.__class__,
4972 decode_path=decode_path,
4976 v, tail = v[:l], v[l:]
4978 sub_offset = offset + tlen + llen
4981 ctx_allow_default_values = ctx.get("allow_default_values", False)
4982 for name, spec in iteritems(self.specs):
4983 if spec.optional and (
4984 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
4988 sub_decode_path = decode_path + (name,)
4990 value, v_tail = spec.decode(
4994 decode_path=sub_decode_path,
4996 _ctx_immutable=False,
4998 except TagMismatch as err:
4999 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5003 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5004 if defined is not None:
5005 defined_by, defined_spec = defined
5006 if issubclass(value.__class__, SequenceOf):
5007 for i, _value in enumerate(value):
5008 sub_sub_decode_path = sub_decode_path + (
5010 DecodePathDefBy(defined_by),
5012 defined_value, defined_tail = defined_spec.decode(
5013 memoryview(bytes(_value)),
5015 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5016 if value.expled else (value.tlen + value.llen)
5019 decode_path=sub_sub_decode_path,
5021 _ctx_immutable=False,
5023 if len(defined_tail) > 0:
5026 klass=self.__class__,
5027 decode_path=sub_sub_decode_path,
5030 _value.defined = (defined_by, defined_value)
5032 defined_value, defined_tail = defined_spec.decode(
5033 memoryview(bytes(value)),
5035 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5036 if value.expled else (value.tlen + value.llen)
5039 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5041 _ctx_immutable=False,
5043 if len(defined_tail) > 0:
5046 klass=self.__class__,
5047 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5050 value.defined = (defined_by, defined_value)
5052 value_len = value.fulllen
5054 sub_offset += value_len
5056 if spec.default is not None and value == spec.default:
5057 if ctx_bered or ctx_allow_default_values:
5061 "DEFAULT value met",
5062 klass=self.__class__,
5063 decode_path=sub_decode_path,
5066 values[name] = value
5068 spec_defines = getattr(spec, "defines", ())
5069 if len(spec_defines) == 0:
5070 defines_by_path = ctx.get("defines_by_path", ())
5071 if len(defines_by_path) > 0:
5072 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5073 if spec_defines is not None and len(spec_defines) > 0:
5074 for rel_path, schema in spec_defines:
5075 defined = schema.get(value, None)
5076 if defined is not None:
5077 ctx.setdefault("_defines", []).append((
5078 abs_decode_path(sub_decode_path[:-1], rel_path),
5082 if v[:EOC_LEN].tobytes() != EOC:
5085 klass=self.__class__,
5086 decode_path=decode_path,
5094 klass=self.__class__,
5095 decode_path=decode_path,
5098 obj = self.__class__(
5102 default=self.default,
5103 optional=self.optional,
5104 _decoded=(offset, llen, vlen),
5107 obj.lenindef = lenindef
5108 obj.ber_encoded = ber_encoded
5112 value = pp_console_row(next(self.pps()))
5114 for name in self.specs:
5115 _value = self._value.get(name)
5118 cols.append("%s: %s" % (name, repr(_value)))
5119 return "%s[%s]" % (value, "; ".join(cols))
5121 def pps(self, decode_path=()):
5124 asn1_type_name=self.asn1_type_name,
5125 obj_name=self.__class__.__name__,
5126 decode_path=decode_path,
5127 optional=self.optional,
5128 default=self == self.default,
5129 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5130 expl=None if self._expl is None else tag_decode(self._expl),
5135 expl_offset=self.expl_offset if self.expled else None,
5136 expl_tlen=self.expl_tlen if self.expled else None,
5137 expl_llen=self.expl_llen if self.expled else None,
5138 expl_vlen=self.expl_vlen if self.expled else None,
5139 expl_lenindef=self.expl_lenindef,
5140 lenindef=self.lenindef,
5141 ber_encoded=self.ber_encoded,
5144 for name in self.specs:
5145 value = self._value.get(name)
5148 yield value.pps(decode_path=decode_path + (name,))
5149 for pp in self.pps_lenindef(decode_path):
5153 class Set(Sequence):
5154 """``SET`` structure type
5156 Its usage is identical to :py:class:`pyderasn.Sequence`.
5158 .. _allow_unordered_set_ctx:
5160 DER prohibits unordered values encoding and will raise an error
5161 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5162 then no error will occure. Also you can disable strict values
5163 ordering check by setting ``"allow_unordered_set": True``
5164 :ref:`context <ctx>` option.
5167 tag_default = tag_encode(form=TagFormConstructed, num=17)
5168 asn1_type_name = "SET"
5171 raws = self._encoded_values()
5174 return b"".join((self.tag, len_encode(len(v)), v))
5176 def _specs_items(self):
5177 return iteritems(self.specs)
5179 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5181 t, tlen, lv = tag_strip(tlv)
5182 except DecodeError as err:
5183 raise err.__class__(
5185 klass=self.__class__,
5186 decode_path=decode_path,
5191 klass=self.__class__,
5192 decode_path=decode_path,
5198 ctx_bered = ctx.get("bered", False)
5200 l, llen, v = len_decode(lv)
5201 except LenIndefForm as err:
5203 raise err.__class__(
5205 klass=self.__class__,
5206 decode_path=decode_path,
5209 l, llen, v = 0, 1, lv[1:]
5211 except DecodeError as err:
5212 raise err.__class__(
5214 klass=self.__class__,
5215 decode_path=decode_path,
5219 raise NotEnoughData(
5220 "encoded length is longer than data",
5221 klass=self.__class__,
5225 v, tail = v[:l], v[l:]
5227 sub_offset = offset + tlen + llen
5230 ctx_allow_default_values = ctx.get("allow_default_values", False)
5231 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5232 value_prev = memoryview(v[:0])
5235 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5237 for name, spec in self._specs_items():
5238 sub_decode_path = decode_path + (name,)
5244 decode_path=sub_decode_path,
5247 _ctx_immutable=False,
5254 klass=self.__class__,
5255 decode_path=decode_path,
5258 value, v_tail = spec.decode(
5262 decode_path=sub_decode_path,
5264 _ctx_immutable=False,
5266 value_len = value.fulllen
5267 if value_prev.tobytes() > v[:value_len].tobytes():
5268 if ctx_bered or ctx_allow_unordered_set:
5272 "unordered " + self.asn1_type_name,
5273 klass=self.__class__,
5274 decode_path=sub_decode_path,
5277 if spec.default is None or value != spec.default:
5279 elif ctx_bered or ctx_allow_default_values:
5283 "DEFAULT value met",
5284 klass=self.__class__,
5285 decode_path=sub_decode_path,
5288 values[name] = value
5289 value_prev = v[:value_len]
5290 sub_offset += value_len
5293 obj = self.__class__(
5297 default=self.default,
5298 optional=self.optional,
5299 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5302 if v[:EOC_LEN].tobytes() != EOC:
5305 klass=self.__class__,
5306 decode_path=decode_path,
5314 "not all values are ready",
5315 klass=self.__class__,
5316 decode_path=decode_path,
5319 obj.ber_encoded = ber_encoded
5323 class SequenceOf(Obj):
5324 """``SEQUENCE OF`` sequence type
5326 For that kind of type you must specify the object it will carry on
5327 (bounds are for example here, not required)::
5329 class Ints(SequenceOf):
5334 >>> ints.append(Integer(123))
5335 >>> ints.append(Integer(234))
5337 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5338 >>> [int(i) for i in ints]
5340 >>> ints.append(Integer(345))
5341 Traceback (most recent call last):
5342 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5345 >>> ints[1] = Integer(345)
5347 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5349 Also you can initialize sequence with preinitialized values:
5351 >>> ints = Ints([Integer(123), Integer(234)])
5353 __slots__ = ("spec", "_bound_min", "_bound_max")
5354 tag_default = tag_encode(form=TagFormConstructed, num=16)
5355 asn1_type_name = "SEQUENCE OF"
5368 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5370 schema = getattr(self, "schema", None)
5372 raise ValueError("schema must be specified")
5374 self._bound_min, self._bound_max = getattr(
5378 ) if bounds is None else bounds
5380 if value is not None:
5381 self._value = self._value_sanitize(value)
5382 if default is not None:
5383 default_value = self._value_sanitize(default)
5384 default_obj = self.__class__(
5389 default_obj._value = default_value
5390 self.default = default_obj
5392 self._value = default_obj.copy()._value
5394 def _value_sanitize(self, value):
5395 if issubclass(value.__class__, SequenceOf):
5396 value = value._value
5397 elif hasattr(value, "__iter__"):
5400 raise InvalidValueType((self.__class__, iter))
5401 if not self._bound_min <= len(value) <= self._bound_max:
5402 raise BoundsError(self._bound_min, len(value), self._bound_max)
5404 if not isinstance(v, self.spec.__class__):
5405 raise InvalidValueType((self.spec.__class__,))
5410 return all(v.ready for v in self._value)
5414 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5416 return any(v.bered for v in self._value)
5419 obj = self.__class__(schema=self.spec)
5420 obj._bound_min = self._bound_min
5421 obj._bound_max = self._bound_max
5423 obj._expl = self._expl
5424 obj.default = self.default
5425 obj.optional = self.optional
5426 obj.offset = self.offset
5427 obj.llen = self.llen
5428 obj.vlen = self.vlen
5429 obj.expl_lenindef = self.expl_lenindef
5430 obj.lenindef = self.lenindef
5431 obj.ber_encoded = self.ber_encoded
5432 obj._value = [v.copy() for v in self._value]
5435 def __eq__(self, their):
5436 if isinstance(their, self.__class__):
5438 self.spec == their.spec and
5439 self.tag == their.tag and
5440 self._expl == their._expl and
5441 self._value == their._value
5443 if hasattr(their, "__iter__"):
5444 return self._value == list(their)
5456 return self.__class__(
5460 (self._bound_min, self._bound_max)
5461 if bounds is None else bounds
5463 impl=self.tag if impl is None else impl,
5464 expl=self._expl if expl is None else expl,
5465 default=self.default if default is None else default,
5466 optional=self.optional if optional is None else optional,
5469 def __contains__(self, key):
5470 return key in self._value
5472 def append(self, value):
5473 if not isinstance(value, self.spec.__class__):
5474 raise InvalidValueType((self.spec.__class__,))
5475 if len(self._value) + 1 > self._bound_max:
5478 len(self._value) + 1,
5481 self._value.append(value)
5484 self._assert_ready()
5485 return iter(self._value)
5488 self._assert_ready()
5489 return len(self._value)
5491 def __setitem__(self, key, value):
5492 if not isinstance(value, self.spec.__class__):
5493 raise InvalidValueType((self.spec.__class__,))
5494 self._value[key] = self.spec(value=value)
5496 def __getitem__(self, key):
5497 return self._value[key]
5499 def _encoded_values(self):
5500 return [v.encode() for v in self._value]
5503 v = b"".join(self._encoded_values())
5504 return b"".join((self.tag, len_encode(len(v)), v))
5506 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5508 t, tlen, lv = tag_strip(tlv)
5509 except DecodeError as err:
5510 raise err.__class__(
5512 klass=self.__class__,
5513 decode_path=decode_path,
5518 klass=self.__class__,
5519 decode_path=decode_path,
5525 ctx_bered = ctx.get("bered", False)
5527 l, llen, v = len_decode(lv)
5528 except LenIndefForm as err:
5530 raise err.__class__(
5532 klass=self.__class__,
5533 decode_path=decode_path,
5536 l, llen, v = 0, 1, lv[1:]
5538 except DecodeError as err:
5539 raise err.__class__(
5541 klass=self.__class__,
5542 decode_path=decode_path,
5546 raise NotEnoughData(
5547 "encoded length is longer than data",
5548 klass=self.__class__,
5549 decode_path=decode_path,
5553 v, tail = v[:l], v[l:]
5555 sub_offset = offset + tlen + llen
5557 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5558 value_prev = memoryview(v[:0])
5562 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5564 sub_decode_path = decode_path + (str(len(_value)),)
5565 value, v_tail = spec.decode(
5569 decode_path=sub_decode_path,
5571 _ctx_immutable=False,
5573 value_len = value.fulllen
5575 if value_prev.tobytes() > v[:value_len].tobytes():
5576 if ctx_bered or ctx_allow_unordered_set:
5580 "unordered " + self.asn1_type_name,
5581 klass=self.__class__,
5582 decode_path=sub_decode_path,
5585 value_prev = v[:value_len]
5586 _value.append(value)
5587 sub_offset += value_len
5591 obj = self.__class__(
5594 bounds=(self._bound_min, self._bound_max),
5597 default=self.default,
5598 optional=self.optional,
5599 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5601 except BoundsError as err:
5604 klass=self.__class__,
5605 decode_path=decode_path,
5609 if v[:EOC_LEN].tobytes() != EOC:
5612 klass=self.__class__,
5613 decode_path=decode_path,
5618 obj.ber_encoded = ber_encoded
5623 pp_console_row(next(self.pps())),
5624 ", ".join(repr(v) for v in self._value),
5627 def pps(self, decode_path=()):
5630 asn1_type_name=self.asn1_type_name,
5631 obj_name=self.__class__.__name__,
5632 decode_path=decode_path,
5633 optional=self.optional,
5634 default=self == self.default,
5635 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5636 expl=None if self._expl is None else tag_decode(self._expl),
5641 expl_offset=self.expl_offset if self.expled else None,
5642 expl_tlen=self.expl_tlen if self.expled else None,
5643 expl_llen=self.expl_llen if self.expled else None,
5644 expl_vlen=self.expl_vlen if self.expled else None,
5645 expl_lenindef=self.expl_lenindef,
5646 lenindef=self.lenindef,
5647 ber_encoded=self.ber_encoded,
5650 for i, value in enumerate(self._value):
5651 yield value.pps(decode_path=decode_path + (str(i),))
5652 for pp in self.pps_lenindef(decode_path):
5656 class SetOf(SequenceOf):
5657 """``SET OF`` sequence type
5659 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
5662 tag_default = tag_encode(form=TagFormConstructed, num=17)
5663 asn1_type_name = "SET OF"
5666 raws = self._encoded_values()
5669 return b"".join((self.tag, len_encode(len(v)), v))
5671 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5672 return super(SetOf, self)._decode(
5678 ordering_check=True,
5682 def obj_by_path(pypath): # pragma: no cover
5683 """Import object specified as string Python path
5685 Modules must be separated from classes/functions with ``:``.
5687 >>> obj_by_path("foo.bar:Baz")
5688 <class 'foo.bar.Baz'>
5689 >>> obj_by_path("foo.bar:Baz.boo")
5690 <classmethod 'foo.bar.Baz.boo'>
5692 mod, objs = pypath.rsplit(":", 1)
5693 from importlib import import_module
5694 obj = import_module(mod)
5695 for obj_name in objs.split("."):
5696 obj = getattr(obj, obj_name)
5700 def generic_decoder(): # pragma: no cover
5701 # All of this below is a big hack with self references
5702 choice = PrimitiveTypes()
5703 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
5704 choice.specs["SetOf"] = SetOf(schema=choice)
5705 for i in six_xrange(31):
5706 choice.specs["SequenceOf%d" % i] = SequenceOf(
5710 choice.specs["Any"] = Any()
5712 # Class name equals to type name, to omit it from output
5713 class SEQUENCEOF(SequenceOf):
5721 with_decode_path=False,
5722 decode_path_only=(),
5724 def _pprint_pps(pps):
5726 if hasattr(pp, "_fields"):
5728 decode_path_only != () and
5729 pp.decode_path[:len(decode_path_only)] != decode_path_only
5732 if pp.asn1_type_name == Choice.asn1_type_name:
5734 pp_kwargs = pp._asdict()
5735 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
5736 pp = _pp(**pp_kwargs)
5737 yield pp_console_row(
5742 with_colours=with_colours,
5743 with_decode_path=with_decode_path,
5744 decode_path_len_decrease=len(decode_path_only),
5746 for row in pp_console_blob(
5748 decode_path_len_decrease=len(decode_path_only),
5752 for row in _pprint_pps(pp):
5754 return "\n".join(_pprint_pps(obj.pps()))
5755 return SEQUENCEOF(), pprint_any
5758 def main(): # pragma: no cover
5760 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
5761 parser.add_argument(
5765 help="Skip that number of bytes from the beginning",
5767 parser.add_argument(
5769 help="Python paths to dictionary with OIDs, comma separated",
5771 parser.add_argument(
5773 help="Python path to schema definition to use",
5775 parser.add_argument(
5776 "--defines-by-path",
5777 help="Python path to decoder's defines_by_path",
5779 parser.add_argument(
5781 action="store_true",
5782 help="Disallow BER encoding",
5784 parser.add_argument(
5785 "--print-decode-path",
5786 action="store_true",
5787 help="Print decode paths",
5789 parser.add_argument(
5790 "--decode-path-only",
5791 help="Print only specified decode path",
5793 parser.add_argument(
5795 action="store_true",
5796 help="Allow explicit tag out-of-bound",
5798 parser.add_argument(
5800 type=argparse.FileType("rb"),
5801 help="Path to DER file you want to decode",
5803 args = parser.parse_args()
5804 args.DERFile.seek(args.skip)
5805 der = memoryview(args.DERFile.read())
5806 args.DERFile.close()
5808 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
5809 if args.oids else ()
5812 schema = obj_by_path(args.schema)
5813 from functools import partial
5814 pprinter = partial(pprint, big_blobs=True)
5816 schema, pprinter = generic_decoder()
5818 "bered": not args.nobered,
5819 "allow_expl_oob": args.allow_expl_oob,
5821 if args.defines_by_path is not None:
5822 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
5823 obj, tail = schema().decode(der, ctx=ctx)
5827 with_colours=environ.get("NO_COLOR") is None,
5828 with_decode_path=args.print_decode_path,
5830 () if args.decode_path_only is None else
5831 tuple(args.decode_path_only.split(":"))
5835 print("\nTrailing data: %s" % hexenc(tail))
5838 if __name__ == "__main__":