3 # cython: language_level=3
4 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
5 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Lesser General Public License as
9 # published by the Free Software Foundation, version 3 of the License.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this program. If not, see <http://www.gnu.org/licenses/>.
18 """Python ASN.1 DER/BER codec with abstract structures
20 This library allows you to marshal various structures in ASN.1 DER
21 format, unmarshal them in BER/CER/DER ones.
25 >>> Integer().decod(raw) == i
28 There are primitive types, holding single values
29 (:py:class:`pyderasn.BitString`,
30 :py:class:`pyderasn.Boolean`,
31 :py:class:`pyderasn.Enumerated`,
32 :py:class:`pyderasn.GeneralizedTime`,
33 :py:class:`pyderasn.Integer`,
34 :py:class:`pyderasn.Null`,
35 :py:class:`pyderasn.ObjectIdentifier`,
36 :py:class:`pyderasn.OctetString`,
37 :py:class:`pyderasn.UTCTime`,
38 :py:class:`various strings <pyderasn.CommonString>`
39 (:py:class:`pyderasn.BMPString`,
40 :py:class:`pyderasn.GeneralString`,
41 :py:class:`pyderasn.GraphicString`,
42 :py:class:`pyderasn.IA5String`,
43 :py:class:`pyderasn.ISO646String`,
44 :py:class:`pyderasn.NumericString`,
45 :py:class:`pyderasn.PrintableString`,
46 :py:class:`pyderasn.T61String`,
47 :py:class:`pyderasn.TeletexString`,
48 :py:class:`pyderasn.UniversalString`,
49 :py:class:`pyderasn.UTF8String`,
50 :py:class:`pyderasn.VideotexString`,
51 :py:class:`pyderasn.VisibleString`)),
52 constructed types, holding multiple primitive types
53 (:py:class:`pyderasn.Sequence`,
54 :py:class:`pyderasn.SequenceOf`,
55 :py:class:`pyderasn.Set`,
56 :py:class:`pyderasn.SetOf`),
57 and special types like
58 :py:class:`pyderasn.Any` and
59 :py:class:`pyderasn.Choice`.
67 Most types in ASN.1 has specific tag for them. ``Obj.tag_default`` is
68 the default tag used during coding process. You can override it with
69 either ``IMPLICIT`` (using either ``impl`` keyword argument or ``impl``
70 class attribute), or ``EXPLICIT`` one (using either ``expl`` keyword
71 argument or ``expl`` class attribute). Both arguments take raw binary
72 string, containing that tag. You can **not** set implicit and explicit
75 There are :py:func:`pyderasn.tag_ctxp` and :py:func:`pyderasn.tag_ctxc`
76 functions, allowing you to easily create ``CONTEXT``
77 ``PRIMITIVE``/``CONSTRUCTED`` tags, by specifying only the required tag
82 EXPLICIT tags always have **constructed** tag. PyDERASN does not
83 explicitly check correctness of schema input here.
87 Implicit tags have **primitive** (``tag_ctxp``) encoding for
92 >>> Integer(impl=tag_ctxp(1))
94 >>> Integer(expl=tag_ctxc(2))
97 Implicit tag is not explicitly shown.
99 Two objects of the same type, but with different implicit/explicit tags
102 You can get object's effective tag (either default or implicited) through
103 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
106 >>> tag_decode(tag_ctxc(123))
108 >>> klass, form, num = tag_decode(tag_ctxc(123))
109 >>> klass == TagClassContext
111 >>> form == TagFormConstructed
114 To determine if object has explicit tag, use ``expled`` boolean property
115 and ``expl_tag`` property, returning explicit tag's value.
120 Many objects in sequences could be ``OPTIONAL`` and could have
121 ``DEFAULT`` value. You can specify that object's property using
122 corresponding keyword arguments.
124 >>> Integer(optional=True, default=123)
125 INTEGER 123 OPTIONAL DEFAULT
127 Those specifications do not play any role in primitive value encoding,
128 but are taken into account when dealing with sequences holding them. For
129 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
132 class Version(Integer):
138 class TBSCertificate(Sequence):
140 ("version", Version(expl=tag_ctxc(0), default="v1")),
143 When default argument is used and value is not specified, then it equals
151 Some objects give ability to set value size constraints. This is either
152 possible integer value, or allowed length of various strings and
153 sequences. Constraints are set in the following way::
158 And values satisfaction is checked as: ``MIN <= X <= MAX``.
160 For simplicity you can also set bounds the following way::
162 bounded_x = X(bounds=(MIN, MAX))
164 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
170 All objects have ``ready`` boolean property, that tells if object is
171 ready to be encoded. If that kind of action is performed on unready
172 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
174 All objects are friendly to ``copy.copy()`` and copied objects can be
177 Also all objects can be safely ``pickle``-d, but pay attention that
178 pickling among different PyDERASN versions is prohibited.
185 Decoding is performed using :py:meth:`pyderasn.Obj.decode` method.
186 ``offset`` optional argument could be used to set initial object's
187 offset in the binary data, for convenience. It returns decoded object
188 and remaining unmarshalled data (tail). Internally all work is done on
189 ``memoryview(data)``, and you can leave returning tail as a memoryview,
190 by specifying ``leavemm=True`` argument.
192 Also note convenient :py:meth:`pyderasn.Obj.decod` method, that
193 immediately checks and raises if there is non-empty tail.
195 When object is decoded, ``decoded`` property is true and you can safely
196 use following properties:
198 * ``offset`` -- position including initial offset where object's tag starts
199 * ``tlen`` -- length of object's tag
200 * ``llen`` -- length of object's length value
201 * ``vlen`` -- length of object's value
202 * ``tlvlen`` -- length of the whole object
204 Pay attention that those values do **not** include anything related to
205 explicit tag. If you want to know information about it, then use:
207 * ``expled`` -- to know if explicit tag is set
208 * ``expl_offset`` (it is lesser than ``offset``)
211 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
212 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
214 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
217 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
224 You can specify so called context keyword argument during
225 :py:meth:`pyderasn.Obj.decode` invocation. It is dictionary containing
226 various options governing decoding process.
228 Currently available context options:
230 * :ref:`allow_default_values <allow_default_values_ctx>`
231 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
232 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
233 * :ref:`bered <bered_ctx>`
234 * :ref:`defines_by_path <defines_by_path_ctx>`
241 All objects have ``pps()`` method, that is a generator of
242 :py:class:`pyderasn.PP` namedtuple, holding various raw information
243 about the object. If ``pps`` is called on sequences, then all underlying
244 ``PP`` will be yielded.
246 You can use :py:func:`pyderasn.pp_console_row` function, converting
247 those ``PP`` to human readable string. Actually exactly it is used for
248 all object ``repr``. But it is easy to write custom formatters.
250 >>> from pyderasn import pprint
251 >>> encoded = Integer(-12345).encode()
252 >>> obj, tail = Integer().decode(encoded)
253 >>> print(pprint(obj))
254 0 [1,1, 2] INTEGER -12345
258 Example certificate::
260 >>> print(pprint(crt))
261 0 [1,3,1604] Certificate SEQUENCE
262 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
263 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
264 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
265 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
266 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
267 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
269 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
270 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
271 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
272 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
273 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
274 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
275 . . . . . . . 13:02:45:53
277 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
278 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
279 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
281 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
282 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
283 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
288 Let's parse that output, human::
290 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
291 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
292 0 1 2 3 4 5 6 7 8 9 10 11
296 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
302 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
308 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
313 Offset of the object, where its DER/BER encoding begins.
314 Pay attention that it does **not** include explicit tag.
316 If explicit tag exists, then this is its length (tag + encoded length).
318 Length of object's tag. For example CHOICE does not have its own tag,
321 Length of encoded length.
323 Length of encoded value.
325 Visual indentation to show the depth of object in the hierarchy.
327 Object's name inside SEQUENCE/CHOICE.
329 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
330 here. "IMPLICIT" is omitted.
332 Object's class name, if set. Omitted if it is just an ordinary simple
333 value (like with ``algorithm`` in example above).
337 Object's value, if set. Can consist of multiple words (like OCTET/BIT
338 STRINGs above). We see ``v3`` value in Version, because it is named.
339 ``rdnSequence`` is the choice of CHOICE type.
341 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
342 default one, specified in the schema.
344 Shows does object contains any kind of BER encoded data (possibly
345 Sequence holding BER-encoded underlying value).
347 Only applicable to BER encoded data. Indefinite length encoding mark.
349 Only applicable to BER encoded data. If object has BER-specific
350 encoding, then ``BER`` will be shown. It does not depend on indefinite
351 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
352 (and its derivatives), ``SET``, ``SET OF``, ``UTCTime``, ``GeneralizedTime``
361 ASN.1 structures often have ANY and OCTET STRING fields, that are
362 DEFINED BY some previously met ObjectIdentifier. This library provides
363 ability to specify mapping between some OID and field that must be
364 decoded with specific specification.
371 :py:class:`pyderasn.ObjectIdentifier` field inside
372 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
373 necessary for decoding structures. For example, CMS (:rfc:`5652`)
376 class ContentInfo(Sequence):
378 ("contentType", ContentType(defines=((("content",), {
379 id_digestedData: DigestedData(),
380 id_signedData: SignedData(),
382 ("content", Any(expl=tag_ctxc(0))),
385 ``contentType`` field tells that it defines that ``content`` must be
386 decoded with ``SignedData`` specification, if ``contentType`` equals to
387 ``id-signedData``. The same applies to ``DigestedData``. If
388 ``contentType`` contains unknown OID, then no automatic decoding is
391 You can specify multiple fields, that will be autodecoded -- that is why
392 ``defines`` kwarg is a sequence. You can specify defined field
393 relatively or absolutely to current decode path. For example ``defines``
394 for AlgorithmIdentifier of X.509's
395 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
399 id_ecPublicKey: ECParameters(),
400 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
402 (("..", "subjectPublicKey"), {
403 id_rsaEncryption: RSAPublicKey(),
404 id_GostR3410_2001: OctetString(),
408 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
409 autodecode its parameters inside SPKI's algorithm and its public key
412 Following types can be automatically decoded (DEFINED BY):
414 * :py:class:`pyderasn.Any`
415 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
416 * :py:class:`pyderasn.OctetString`
417 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
418 ``Any``/``BitString``/``OctetString``-s
420 When any of those fields is automatically decoded, then ``.defined``
421 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
422 was defined, ``value`` contains corresponding decoded value. For example
423 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
425 .. _defines_by_path_ctx:
427 defines_by_path context option
428 ______________________________
430 Sometimes you either can not or do not want to explicitly set *defines*
431 in the scheme. You can dynamically apply those definitions when calling
432 ``.decode()`` method.
434 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
435 value must be sequence of following tuples::
437 (decode_path, defines)
439 where ``decode_path`` is a tuple holding so-called decode path to the
440 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
441 ``defines``, holding exactly the same value as accepted in its
442 :ref:`keyword argument <defines>`.
444 For example, again for CMS, you want to automatically decode
445 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
446 structures it may hold. Also, automatically decode ``controlSequence``
449 content_info = ContentInfo().decod(data, ctx={"defines_by_path": (
452 ((("content",), {id_signedData: SignedData()}),),
457 DecodePathDefBy(id_signedData),
462 id_cct_PKIData: PKIData(),
463 id_cct_PKIResponse: PKIResponse(),
469 DecodePathDefBy(id_signedData),
472 DecodePathDefBy(id_cct_PKIResponse),
478 id_cmc_recipientNonce: RecipientNonce(),
479 id_cmc_senderNonce: SenderNonce(),
480 id_cmc_statusInfoV2: CMCStatusInfoV2(),
481 id_cmc_transactionId: TransactionId(),
486 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
487 First function is useful for path construction when some automatic
488 decoding is already done. ``any`` means literally any value it meet --
489 useful for SEQUENCE/SET OF-s.
496 By default PyDERASN accepts only DER encoded data. It always encodes to
497 DER. But you can optionally enable BER decoding with setting ``bered``
498 :ref:`context <ctx>` argument to True. Indefinite lengths and
499 constructed primitive types should be parsed successfully.
501 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
502 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
503 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``,
504 ``UTCTime``, ``GeneralizedTime`` can contain it.
505 * If object has an indefinite length encoding, then its ``lenindef``
506 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
507 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
509 * If object has an indefinite length encoded explicit tag, then
510 ``expl_lenindef`` is set to True.
511 * If object has either any of BER-related encoding (explicit tag
512 indefinite length, object's indefinite length, BER-encoding) or any
513 underlying component has that kind of encoding, then ``bered``
514 attribute is set to True. For example SignedData CMS can have
515 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
516 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
518 EOC (end-of-contents) token's length is taken in advance in object's
521 .. _allow_expl_oob_ctx:
523 Allow explicit tag out-of-bound
524 -------------------------------
526 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
527 one value, more than one object. If you set ``allow_expl_oob`` context
528 option to True, then no error will be raised and that invalid encoding
529 will be silently further processed. But pay attention that offsets and
530 lengths will be invalid in that case.
534 This option should be used only for skipping some decode errors, just
535 to see the decoded structure somehow.
539 .. autoclass:: pyderasn.Obj
547 .. autoclass:: pyderasn.Boolean
552 .. autoclass:: pyderasn.Integer
557 .. autoclass:: pyderasn.BitString
562 .. autoclass:: pyderasn.OctetString
567 .. autoclass:: pyderasn.Null
572 .. autoclass:: pyderasn.ObjectIdentifier
577 .. autoclass:: pyderasn.Enumerated
581 .. autoclass:: pyderasn.CommonString
585 .. autoclass:: pyderasn.NumericString
589 .. autoclass:: pyderasn.PrintableString
594 .. autoclass:: pyderasn.UTCTime
595 :members: __init__, todatetime
599 .. autoclass:: pyderasn.GeneralizedTime
606 .. autoclass:: pyderasn.Choice
611 .. autoclass:: PrimitiveTypes
615 .. autoclass:: pyderasn.Any
623 .. autoclass:: pyderasn.Sequence
628 .. autoclass:: pyderasn.Set
633 .. autoclass:: pyderasn.SequenceOf
638 .. autoclass:: pyderasn.SetOf
644 .. autofunction:: pyderasn.abs_decode_path
645 .. autofunction:: pyderasn.colonize_hex
646 .. autofunction:: pyderasn.hexenc
647 .. autofunction:: pyderasn.hexdec
648 .. autofunction:: pyderasn.tag_encode
649 .. autofunction:: pyderasn.tag_decode
650 .. autofunction:: pyderasn.tag_ctxp
651 .. autofunction:: pyderasn.tag_ctxc
652 .. autoclass:: pyderasn.DecodeError
654 .. autoclass:: pyderasn.NotEnoughData
655 .. autoclass:: pyderasn.ExceedingData
656 .. autoclass:: pyderasn.LenIndefForm
657 .. autoclass:: pyderasn.TagMismatch
658 .. autoclass:: pyderasn.InvalidLength
659 .. autoclass:: pyderasn.InvalidOID
660 .. autoclass:: pyderasn.ObjUnknown
661 .. autoclass:: pyderasn.ObjNotReady
662 .. autoclass:: pyderasn.InvalidValueType
663 .. autoclass:: pyderasn.BoundsError
666 from codecs import getdecoder
667 from codecs import getencoder
668 from collections import namedtuple
669 from collections import OrderedDict
670 from copy import copy
671 from datetime import datetime
672 from datetime import timedelta
673 from math import ceil
674 from os import environ
675 from string import ascii_letters
676 from string import digits
677 from sys import version_info
678 from unicodedata import category as unicat
680 from six import add_metaclass
681 from six import binary_type
682 from six import byte2int
683 from six import indexbytes
684 from six import int2byte
685 from six import integer_types
686 from six import iterbytes
687 from six import iteritems
688 from six import itervalues
690 from six import string_types
691 from six import text_type
692 from six import unichr as six_unichr
693 from six.moves import xrange as six_xrange
697 from termcolor import colored
698 except ImportError: # pragma: no cover
699 def colored(what, *args, **kwargs):
745 "TagClassApplication",
749 "TagFormConstructed",
760 TagClassUniversal = 0
761 TagClassApplication = 1 << 6
762 TagClassContext = 1 << 7
763 TagClassPrivate = 1 << 6 | 1 << 7
765 TagFormConstructed = 1 << 5
768 TagClassApplication: "APPLICATION ",
769 TagClassPrivate: "PRIVATE ",
770 TagClassUniversal: "UNIV ",
774 LENINDEF = b"\x80" # length indefinite mark
775 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
776 NAMEDTUPLE_KWARGS = {} if version_info < (3, 6) else {"module": __name__}
777 SET01 = frozenset("01")
778 DECIMALS = frozenset(digits)
783 if not set(value) <= DECIMALS:
784 raise ValueError("non-pure integer")
787 def fractions2float(fractions_raw):
788 pureint(fractions_raw)
789 return float("0." + fractions_raw)
792 ########################################################################
794 ########################################################################
796 class ASN1Error(ValueError):
800 class DecodeError(ASN1Error):
801 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
803 :param str msg: reason of decode failing
804 :param klass: optional exact DecodeError inherited class (like
805 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
806 :py:exc:`InvalidLength`)
807 :param decode_path: tuple of strings. It contains human
808 readable names of the fields through which
809 decoding process has passed
810 :param int offset: binary offset where failure happened
812 super(DecodeError, self).__init__()
815 self.decode_path = decode_path
821 "" if self.klass is None else self.klass.__name__,
823 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
824 if len(self.decode_path) > 0 else ""
826 ("(at %d)" % self.offset) if self.offset > 0 else "",
832 return "%s(%s)" % (self.__class__.__name__, self)
835 class NotEnoughData(DecodeError):
839 class ExceedingData(ASN1Error):
840 def __init__(self, nbytes):
841 super(ExceedingData, self).__init__()
845 return "%d trailing bytes" % self.nbytes
848 return "%s(%s)" % (self.__class__.__name__, self)
851 class LenIndefForm(DecodeError):
855 class TagMismatch(DecodeError):
859 class InvalidLength(DecodeError):
863 class InvalidOID(DecodeError):
867 class ObjUnknown(ASN1Error):
868 def __init__(self, name):
869 super(ObjUnknown, self).__init__()
873 return "object is unknown: %s" % self.name
876 return "%s(%s)" % (self.__class__.__name__, self)
879 class ObjNotReady(ASN1Error):
880 def __init__(self, name):
881 super(ObjNotReady, self).__init__()
885 return "object is not ready: %s" % self.name
888 return "%s(%s)" % (self.__class__.__name__, self)
891 class InvalidValueType(ASN1Error):
892 def __init__(self, expected_types):
893 super(InvalidValueType, self).__init__()
894 self.expected_types = expected_types
897 return "invalid value type, expected: %s" % ", ".join(
898 [repr(t) for t in self.expected_types]
902 return "%s(%s)" % (self.__class__.__name__, self)
905 class BoundsError(ASN1Error):
906 def __init__(self, bound_min, value, bound_max):
907 super(BoundsError, self).__init__()
908 self.bound_min = bound_min
910 self.bound_max = bound_max
913 return "unsatisfied bounds: %s <= %s <= %s" % (
920 return "%s(%s)" % (self.__class__.__name__, self)
923 ########################################################################
925 ########################################################################
927 _hexdecoder = getdecoder("hex")
928 _hexencoder = getencoder("hex")
932 """Binary data to hexadecimal string convert
934 return _hexdecoder(data)[0]
938 """Hexadecimal string to binary data convert
940 return _hexencoder(data)[0].decode("ascii")
943 def int_bytes_len(num, byte_len=8):
946 return int(ceil(float(num.bit_length()) / byte_len))
949 def zero_ended_encode(num):
950 octets = bytearray(int_bytes_len(num, 7))
952 octets[i] = num & 0x7F
956 octets[i] = 0x80 | (num & 0x7F)
962 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
963 """Encode tag to binary form
965 :param int num: tag's number
966 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
967 :py:data:`pyderasn.TagClassContext`,
968 :py:data:`pyderasn.TagClassApplication`,
969 :py:data:`pyderasn.TagClassPrivate`)
970 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
971 :py:data:`pyderasn.TagFormConstructed`)
975 return int2byte(klass | form | num)
976 # [XX|X|11111][1.......][1.......] ... [0.......]
977 return int2byte(klass | form | 31) + zero_ended_encode(num)
981 """Decode tag from binary form
985 No validation is performed, assuming that it has already passed.
987 It returns tuple with three integers, as
988 :py:func:`pyderasn.tag_encode` accepts.
990 first_octet = byte2int(tag)
991 klass = first_octet & 0xC0
992 form = first_octet & 0x20
993 if first_octet & 0x1F < 0x1F:
994 return (klass, form, first_octet & 0x1F)
996 for octet in iterbytes(tag[1:]):
999 return (klass, form, num)
1003 """Create CONTEXT PRIMITIVE tag
1005 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
1009 """Create CONTEXT CONSTRUCTED tag
1011 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
1014 def tag_strip(data):
1015 """Take off tag from the data
1017 :returns: (encoded tag, tag length, remaining data)
1020 raise NotEnoughData("no data at all")
1021 if byte2int(data) & 0x1F < 31:
1022 return data[:1], 1, data[1:]
1027 raise DecodeError("unfinished tag")
1028 if indexbytes(data, i) & 0x80 == 0:
1031 return data[:i], i, data[i:]
1037 octets = bytearray(int_bytes_len(l) + 1)
1038 octets[0] = 0x80 | (len(octets) - 1)
1039 for i in six_xrange(len(octets) - 1, 0, -1):
1040 octets[i] = l & 0xFF
1042 return bytes(octets)
1045 def len_decode(data):
1048 :returns: (decoded length, length's length, remaining data)
1049 :raises LenIndefForm: if indefinite form encoding is met
1052 raise NotEnoughData("no data at all")
1053 first_octet = byte2int(data)
1054 if first_octet & 0x80 == 0:
1055 return first_octet, 1, data[1:]
1056 octets_num = first_octet & 0x7F
1057 if octets_num + 1 > len(data):
1058 raise NotEnoughData("encoded length is longer than data")
1060 raise LenIndefForm()
1061 if byte2int(data[1:]) == 0:
1062 raise DecodeError("leading zeros")
1064 for v in iterbytes(data[1:1 + octets_num]):
1067 raise DecodeError("long form instead of short one")
1068 return l, 1 + octets_num, data[1 + octets_num:]
1071 ########################################################################
1073 ########################################################################
1075 class AutoAddSlots(type):
1076 def __new__(cls, name, bases, _dict):
1077 _dict["__slots__"] = _dict.get("__slots__", ())
1078 return type.__new__(cls, name, bases, _dict)
1081 @add_metaclass(AutoAddSlots)
1083 """Common ASN.1 object class
1085 All ASN.1 types are inherited from it. It has metaclass that
1086 automatically adds ``__slots__`` to all inherited classes.
1110 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1111 self._expl = getattr(self, "expl", None) if expl is None else expl
1112 if self.tag != self.tag_default and self._expl is not None:
1113 raise ValueError("implicit and explicit tags can not be set simultaneously")
1114 if default is not None:
1116 self.optional = optional
1117 self.offset, self.llen, self.vlen = _decoded
1119 self.expl_lenindef = False
1120 self.lenindef = False
1121 self.ber_encoded = False
1124 def ready(self): # pragma: no cover
1125 """Is object ready to be encoded?
1127 raise NotImplementedError()
1129 def _assert_ready(self):
1131 raise ObjNotReady(self.__class__.__name__)
1135 """Is either object or any elements inside is BER encoded?
1137 return self.expl_lenindef or self.lenindef or self.ber_encoded
1141 """Is object decoded?
1143 return (self.llen + self.vlen) > 0
1145 def __getstate__(self): # pragma: no cover
1146 """Used for making safe to be mutable pickleable copies
1148 raise NotImplementedError()
1150 def __setstate__(self, state):
1151 if state.version != __version__:
1152 raise ValueError("data is pickled by different PyDERASN version")
1153 self.tag = self.tag_default
1157 self.optional = False
1161 self.expl_lenindef = False
1162 self.lenindef = False
1163 self.ber_encoded = False
1167 """See :ref:`decoding`
1169 return len(self.tag)
1173 """See :ref:`decoding`
1175 return self.tlen + self.llen + self.vlen
1177 def __str__(self): # pragma: no cover
1178 return self.__bytes__() if PY2 else self.__unicode__()
1180 def __ne__(self, their):
1181 return not(self == their)
1183 def __gt__(self, their): # pragma: no cover
1184 return not(self < their)
1186 def __le__(self, their): # pragma: no cover
1187 return (self == their) or (self < their)
1189 def __ge__(self, their): # pragma: no cover
1190 return (self == their) or (self > their)
1192 def _encode(self): # pragma: no cover
1193 raise NotImplementedError()
1195 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1196 raise NotImplementedError()
1199 """Encode the structure
1201 :returns: DER representation
1203 raw = self._encode()
1204 if self._expl is None:
1206 return b"".join((self._expl, len_encode(len(raw)), raw))
1208 def hexencode(self):
1209 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1211 return hexenc(self.encode())
1221 _ctx_immutable=True,
1225 :param data: either binary or memoryview
1226 :param int offset: initial data's offset
1227 :param bool leavemm: do we need to leave memoryview of remaining
1228 data as is, or convert it to bytes otherwise
1229 :param ctx: optional :ref:`context <ctx>` governing decoding process
1230 :param tag_only: decode only the tag, without length and contents
1231 (used only in Choice and Set structures, trying to
1232 determine if tag satisfies the scheme)
1233 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1235 :returns: (Obj, remaining data)
1237 .. seealso:: :ref:`decoding`
1241 elif _ctx_immutable:
1243 tlv = memoryview(data)
1244 if self._expl is None:
1245 result = self._decode(
1248 decode_path=decode_path,
1257 t, tlen, lv = tag_strip(tlv)
1258 except DecodeError as err:
1259 raise err.__class__(
1261 klass=self.__class__,
1262 decode_path=decode_path,
1267 klass=self.__class__,
1268 decode_path=decode_path,
1272 l, llen, v = len_decode(lv)
1273 except LenIndefForm as err:
1274 if not ctx.get("bered", False):
1275 raise err.__class__(
1277 klass=self.__class__,
1278 decode_path=decode_path,
1282 offset += tlen + llen
1283 result = self._decode(
1286 decode_path=decode_path,
1290 if tag_only: # pragma: no cover
1293 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1294 if eoc_expected.tobytes() != EOC:
1297 klass=self.__class__,
1298 decode_path=decode_path,
1302 obj.expl_lenindef = True
1303 except DecodeError as err:
1304 raise err.__class__(
1306 klass=self.__class__,
1307 decode_path=decode_path,
1312 raise NotEnoughData(
1313 "encoded length is longer than data",
1314 klass=self.__class__,
1315 decode_path=decode_path,
1318 result = self._decode(
1320 offset=offset + tlen + llen,
1321 decode_path=decode_path,
1325 if tag_only: # pragma: no cover
1328 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1330 "explicit tag out-of-bound, longer than data",
1331 klass=self.__class__,
1332 decode_path=decode_path,
1335 return obj, (tail if leavemm else tail.tobytes())
1337 def decod(self, data, offset=0, decode_path=(), ctx=None):
1338 """Decode the data, check that tail is empty
1340 :raises ExceedingData: if tail is not empty
1342 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1343 (decode without tail) that also checks that there is no
1346 obj, tail = self.decode(
1349 decode_path=decode_path,
1354 raise ExceedingData(len(tail))
1357 def hexdecode(self, data, *args, **kwargs):
1358 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1360 return self.decode(hexdec(data), *args, **kwargs)
1362 def hexdecod(self, data, *args, **kwargs):
1363 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1365 return self.decod(hexdec(data), *args, **kwargs)
1369 """See :ref:`decoding`
1371 return self._expl is not None
1375 """See :ref:`decoding`
1380 def expl_tlen(self):
1381 """See :ref:`decoding`
1383 return len(self._expl)
1386 def expl_llen(self):
1387 """See :ref:`decoding`
1389 if self.expl_lenindef:
1391 return len(len_encode(self.tlvlen))
1394 def expl_offset(self):
1395 """See :ref:`decoding`
1397 return self.offset - self.expl_tlen - self.expl_llen
1400 def expl_vlen(self):
1401 """See :ref:`decoding`
1406 def expl_tlvlen(self):
1407 """See :ref:`decoding`
1409 return self.expl_tlen + self.expl_llen + self.expl_vlen
1412 def fulloffset(self):
1413 """See :ref:`decoding`
1415 return self.expl_offset if self.expled else self.offset
1419 """See :ref:`decoding`
1421 return self.expl_tlvlen if self.expled else self.tlvlen
1423 def pps_lenindef(self, decode_path):
1424 if self.lenindef and not (
1425 getattr(self, "defined", None) is not None and
1426 self.defined[1].lenindef
1429 asn1_type_name="EOC",
1431 decode_path=decode_path,
1433 self.offset + self.tlvlen -
1434 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1442 if self.expl_lenindef:
1444 asn1_type_name="EOC",
1445 obj_name="EXPLICIT",
1446 decode_path=decode_path,
1447 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1456 class DecodePathDefBy(object):
1457 """DEFINED BY representation inside decode path
1459 __slots__ = ("defined_by",)
1461 def __init__(self, defined_by):
1462 self.defined_by = defined_by
1464 def __ne__(self, their):
1465 return not(self == their)
1467 def __eq__(self, their):
1468 if not isinstance(their, self.__class__):
1470 return self.defined_by == their.defined_by
1473 return "DEFINED BY " + str(self.defined_by)
1476 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1479 ########################################################################
1481 ########################################################################
1483 PP = namedtuple("PP", (
1506 ), **NAMEDTUPLE_KWARGS)
1511 asn1_type_name="unknown",
1528 expl_lenindef=False,
1559 def _colourize(what, colour, with_colours, attrs=("bold",)):
1560 return colored(what, colour, attrs=attrs) if with_colours else what
1563 def colonize_hex(hexed):
1564 """Separate hexadecimal string with colons
1566 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1575 with_decode_path=False,
1576 decode_path_len_decrease=0,
1583 " " if pp.expl_offset is None else
1584 ("-%d" % (pp.offset - pp.expl_offset))
1586 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1588 col = _colourize(col, "red", with_colours, ())
1589 col += _colourize("B", "red", with_colours) if pp.bered else " "
1591 col = "[%d,%d,%4d]%s" % (
1595 LENINDEF_PP_CHAR if pp.lenindef else " "
1597 col = _colourize(col, "green", with_colours, ())
1599 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1600 if decode_path_len > 0:
1601 cols.append(" ." * decode_path_len)
1602 ent = pp.decode_path[-1]
1603 if isinstance(ent, DecodePathDefBy):
1604 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1605 value = str(ent.defined_by)
1608 len(oid_maps) > 0 and
1609 ent.defined_by.asn1_type_name ==
1610 ObjectIdentifier.asn1_type_name
1612 for oid_map in oid_maps:
1613 oid_name = oid_map.get(value)
1614 if oid_name is not None:
1615 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1617 if oid_name is None:
1618 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1620 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1621 if pp.expl is not None:
1622 klass, _, num = pp.expl
1623 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1624 cols.append(_colourize(col, "blue", with_colours))
1625 if pp.impl is not None:
1626 klass, _, num = pp.impl
1627 col = "[%s%d]" % (TagClassReprs[klass], num)
1628 cols.append(_colourize(col, "blue", with_colours))
1629 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1630 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1632 cols.append(_colourize("BER", "red", with_colours))
1633 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1634 if pp.value is not None:
1636 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1638 len(oid_maps) > 0 and
1639 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1641 for oid_map in oid_maps:
1642 oid_name = oid_map.get(value)
1643 if oid_name is not None:
1644 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1646 if pp.asn1_type_name == Integer.asn1_type_name:
1647 hex_repr = hex(int(pp.obj._value))[2:].upper()
1648 if len(hex_repr) % 2 != 0:
1649 hex_repr = "0" + hex_repr
1650 cols.append(_colourize(
1651 "(%s)" % colonize_hex(hex_repr),
1656 if pp.blob.__class__ == binary_type:
1657 cols.append(hexenc(pp.blob))
1658 elif pp.blob.__class__ == tuple:
1659 cols.append(", ".join(pp.blob))
1661 cols.append(_colourize("OPTIONAL", "red", with_colours))
1663 cols.append(_colourize("DEFAULT", "red", with_colours))
1664 if with_decode_path:
1665 cols.append(_colourize(
1666 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1670 return " ".join(cols)
1673 def pp_console_blob(pp, decode_path_len_decrease=0):
1674 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1675 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1676 if decode_path_len > 0:
1677 cols.append(" ." * (decode_path_len + 1))
1678 if pp.blob.__class__ == binary_type:
1679 blob = hexenc(pp.blob).upper()
1680 for i in six_xrange(0, len(blob), 32):
1681 chunk = blob[i:i + 32]
1682 yield " ".join(cols + [colonize_hex(chunk)])
1683 elif pp.blob.__class__ == tuple:
1684 yield " ".join(cols + [", ".join(pp.blob)])
1692 with_decode_path=False,
1693 decode_path_only=(),
1695 """Pretty print object
1697 :param Obj obj: object you want to pretty print
1698 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1699 Its human readable form is printed when OID is met
1700 :param big_blobs: if large binary objects are met (like OctetString
1701 values), do we need to print them too, on separate
1703 :param with_colours: colourize output, if ``termcolor`` library
1705 :param with_decode_path: print decode path
1706 :param decode_path_only: print only that specified decode path
1708 def _pprint_pps(pps):
1710 if hasattr(pp, "_fields"):
1712 decode_path_only != () and
1714 str(p) for p in pp.decode_path[:len(decode_path_only)]
1715 ) != decode_path_only
1719 yield pp_console_row(
1724 with_colours=with_colours,
1725 with_decode_path=with_decode_path,
1726 decode_path_len_decrease=len(decode_path_only),
1728 for row in pp_console_blob(
1730 decode_path_len_decrease=len(decode_path_only),
1734 yield pp_console_row(
1739 with_colours=with_colours,
1740 with_decode_path=with_decode_path,
1741 decode_path_len_decrease=len(decode_path_only),
1744 for row in _pprint_pps(pp):
1746 return "\n".join(_pprint_pps(obj.pps()))
1749 ########################################################################
1750 # ASN.1 primitive types
1751 ########################################################################
1753 BooleanState = namedtuple("BooleanState", (
1766 ), **NAMEDTUPLE_KWARGS)
1770 """``BOOLEAN`` boolean type
1772 >>> b = Boolean(True)
1774 >>> b == Boolean(True)
1780 tag_default = tag_encode(1)
1781 asn1_type_name = "BOOLEAN"
1793 :param value: set the value. Either boolean type, or
1794 :py:class:`pyderasn.Boolean` object
1795 :param bytes impl: override default tag with ``IMPLICIT`` one
1796 :param bytes expl: override default tag with ``EXPLICIT`` one
1797 :param default: set default value. Type same as in ``value``
1798 :param bool optional: is object ``OPTIONAL`` in sequence
1800 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1801 self._value = None if value is None else self._value_sanitize(value)
1802 if default is not None:
1803 default = self._value_sanitize(default)
1804 self.default = self.__class__(
1810 self._value = default
1812 def _value_sanitize(self, value):
1813 if value.__class__ == bool:
1815 if issubclass(value.__class__, Boolean):
1817 raise InvalidValueType((self.__class__, bool))
1821 return self._value is not None
1823 def __getstate__(self):
1824 return BooleanState(
1839 def __setstate__(self, state):
1840 super(Boolean, self).__setstate__(state)
1841 self._value = state.value
1842 self.tag = state.tag
1843 self._expl = state.expl
1844 self.default = state.default
1845 self.optional = state.optional
1846 self.offset = state.offset
1847 self.llen = state.llen
1848 self.vlen = state.vlen
1849 self.expl_lenindef = state.expl_lenindef
1850 self.lenindef = state.lenindef
1851 self.ber_encoded = state.ber_encoded
1853 def __nonzero__(self):
1854 self._assert_ready()
1858 self._assert_ready()
1861 def __eq__(self, their):
1862 if their.__class__ == bool:
1863 return self._value == their
1864 if not issubclass(their.__class__, Boolean):
1867 self._value == their._value and
1868 self.tag == their.tag and
1869 self._expl == their._expl
1880 return self.__class__(
1882 impl=self.tag if impl is None else impl,
1883 expl=self._expl if expl is None else expl,
1884 default=self.default if default is None else default,
1885 optional=self.optional if optional is None else optional,
1889 self._assert_ready()
1893 (b"\xFF" if self._value else b"\x00"),
1896 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1898 t, _, lv = tag_strip(tlv)
1899 except DecodeError as err:
1900 raise err.__class__(
1902 klass=self.__class__,
1903 decode_path=decode_path,
1908 klass=self.__class__,
1909 decode_path=decode_path,
1915 l, _, v = len_decode(lv)
1916 except DecodeError as err:
1917 raise err.__class__(
1919 klass=self.__class__,
1920 decode_path=decode_path,
1924 raise InvalidLength(
1925 "Boolean's length must be equal to 1",
1926 klass=self.__class__,
1927 decode_path=decode_path,
1931 raise NotEnoughData(
1932 "encoded length is longer than data",
1933 klass=self.__class__,
1934 decode_path=decode_path,
1937 first_octet = byte2int(v)
1939 if first_octet == 0:
1941 elif first_octet == 0xFF:
1943 elif ctx.get("bered", False):
1948 "unacceptable Boolean value",
1949 klass=self.__class__,
1950 decode_path=decode_path,
1953 obj = self.__class__(
1957 default=self.default,
1958 optional=self.optional,
1959 _decoded=(offset, 1, 1),
1961 obj.ber_encoded = ber_encoded
1965 return pp_console_row(next(self.pps()))
1967 def pps(self, decode_path=()):
1970 asn1_type_name=self.asn1_type_name,
1971 obj_name=self.__class__.__name__,
1972 decode_path=decode_path,
1973 value=str(self._value) if self.ready else None,
1974 optional=self.optional,
1975 default=self == self.default,
1976 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1977 expl=None if self._expl is None else tag_decode(self._expl),
1982 expl_offset=self.expl_offset if self.expled else None,
1983 expl_tlen=self.expl_tlen if self.expled else None,
1984 expl_llen=self.expl_llen if self.expled else None,
1985 expl_vlen=self.expl_vlen if self.expled else None,
1986 expl_lenindef=self.expl_lenindef,
1987 ber_encoded=self.ber_encoded,
1990 for pp in self.pps_lenindef(decode_path):
1994 IntegerState = namedtuple("IntegerState", (
2010 ), **NAMEDTUPLE_KWARGS)
2014 """``INTEGER`` integer type
2016 >>> b = Integer(-123)
2018 >>> b == Integer(-123)
2023 >>> Integer(2, bounds=(1, 3))
2025 >>> Integer(5, bounds=(1, 3))
2026 Traceback (most recent call last):
2027 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2031 class Version(Integer):
2038 >>> v = Version("v1")
2045 {'v3': 2, 'v1': 0, 'v2': 1}
2047 __slots__ = ("specs", "_bound_min", "_bound_max")
2048 tag_default = tag_encode(2)
2049 asn1_type_name = "INTEGER"
2063 :param value: set the value. Either integer type, named value
2064 (if ``schema`` is specified in the class), or
2065 :py:class:`pyderasn.Integer` object
2066 :param bounds: set ``(MIN, MAX)`` value constraint.
2067 (-inf, +inf) by default
2068 :param bytes impl: override default tag with ``IMPLICIT`` one
2069 :param bytes expl: override default tag with ``EXPLICIT`` one
2070 :param default: set default value. Type same as in ``value``
2071 :param bool optional: is object ``OPTIONAL`` in sequence
2073 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2075 specs = getattr(self, "schema", {}) if _specs is None else _specs
2076 self.specs = specs if specs.__class__ == dict else dict(specs)
2077 self._bound_min, self._bound_max = getattr(
2080 (float("-inf"), float("+inf")),
2081 ) if bounds is None else bounds
2082 if value is not None:
2083 self._value = self._value_sanitize(value)
2084 if default is not None:
2085 default = self._value_sanitize(default)
2086 self.default = self.__class__(
2092 if self._value is None:
2093 self._value = default
2095 def _value_sanitize(self, value):
2096 if isinstance(value, integer_types):
2098 elif issubclass(value.__class__, Integer):
2099 value = value._value
2100 elif value.__class__ == str:
2101 value = self.specs.get(value)
2103 raise ObjUnknown("integer value: %s" % value)
2105 raise InvalidValueType((self.__class__, int, str))
2106 if not self._bound_min <= value <= self._bound_max:
2107 raise BoundsError(self._bound_min, value, self._bound_max)
2112 return self._value is not None
2114 def __getstate__(self):
2115 return IntegerState(
2133 def __setstate__(self, state):
2134 super(Integer, self).__setstate__(state)
2135 self.specs = state.specs
2136 self._value = state.value
2137 self._bound_min = state.bound_min
2138 self._bound_max = state.bound_max
2139 self.tag = state.tag
2140 self._expl = state.expl
2141 self.default = state.default
2142 self.optional = state.optional
2143 self.offset = state.offset
2144 self.llen = state.llen
2145 self.vlen = state.vlen
2146 self.expl_lenindef = state.expl_lenindef
2147 self.lenindef = state.lenindef
2148 self.ber_encoded = state.ber_encoded
2151 self._assert_ready()
2152 return int(self._value)
2155 self._assert_ready()
2158 bytes(self._expl or b"") +
2159 str(self._value).encode("ascii"),
2162 def __eq__(self, their):
2163 if isinstance(their, integer_types):
2164 return self._value == their
2165 if not issubclass(their.__class__, Integer):
2168 self._value == their._value and
2169 self.tag == their.tag and
2170 self._expl == their._expl
2173 def __lt__(self, their):
2174 return self._value < their._value
2178 for name, value in iteritems(self.specs):
2179 if value == self._value:
2192 return self.__class__(
2195 (self._bound_min, self._bound_max)
2196 if bounds is None else bounds
2198 impl=self.tag if impl is None else impl,
2199 expl=self._expl if expl is None else expl,
2200 default=self.default if default is None else default,
2201 optional=self.optional if optional is None else optional,
2206 self._assert_ready()
2210 octets = bytearray([0])
2214 octets = bytearray()
2216 octets.append((value & 0xFF) ^ 0xFF)
2218 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2221 octets = bytearray()
2223 octets.append(value & 0xFF)
2225 if octets[-1] & 0x80 > 0:
2228 octets = bytes(octets)
2230 bytes_len = ceil(value.bit_length() / 8) or 1
2233 octets = value.to_bytes(
2238 except OverflowError:
2242 return b"".join((self.tag, len_encode(len(octets)), octets))
2244 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2246 t, _, lv = tag_strip(tlv)
2247 except DecodeError as err:
2248 raise err.__class__(
2250 klass=self.__class__,
2251 decode_path=decode_path,
2256 klass=self.__class__,
2257 decode_path=decode_path,
2263 l, llen, v = len_decode(lv)
2264 except DecodeError as err:
2265 raise err.__class__(
2267 klass=self.__class__,
2268 decode_path=decode_path,
2272 raise NotEnoughData(
2273 "encoded length is longer than data",
2274 klass=self.__class__,
2275 decode_path=decode_path,
2279 raise NotEnoughData(
2281 klass=self.__class__,
2282 decode_path=decode_path,
2285 v, tail = v[:l], v[l:]
2286 first_octet = byte2int(v)
2288 second_octet = byte2int(v[1:])
2290 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2291 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2294 "non normalized integer",
2295 klass=self.__class__,
2296 decode_path=decode_path,
2301 if first_octet & 0x80 > 0:
2302 octets = bytearray()
2303 for octet in bytearray(v):
2304 octets.append(octet ^ 0xFF)
2305 for octet in octets:
2306 value = (value << 8) | octet
2310 for octet in bytearray(v):
2311 value = (value << 8) | octet
2313 value = int.from_bytes(v, byteorder="big", signed=True)
2315 obj = self.__class__(
2317 bounds=(self._bound_min, self._bound_max),
2320 default=self.default,
2321 optional=self.optional,
2323 _decoded=(offset, llen, l),
2325 except BoundsError as err:
2328 klass=self.__class__,
2329 decode_path=decode_path,
2335 return pp_console_row(next(self.pps()))
2337 def pps(self, decode_path=()):
2340 asn1_type_name=self.asn1_type_name,
2341 obj_name=self.__class__.__name__,
2342 decode_path=decode_path,
2343 value=(self.named or str(self._value)) if self.ready else None,
2344 optional=self.optional,
2345 default=self == self.default,
2346 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2347 expl=None if self._expl is None else tag_decode(self._expl),
2352 expl_offset=self.expl_offset if self.expled else None,
2353 expl_tlen=self.expl_tlen if self.expled else None,
2354 expl_llen=self.expl_llen if self.expled else None,
2355 expl_vlen=self.expl_vlen if self.expled else None,
2356 expl_lenindef=self.expl_lenindef,
2359 for pp in self.pps_lenindef(decode_path):
2363 BitStringState = namedtuple("BitStringState", (
2379 ), **NAMEDTUPLE_KWARGS)
2382 class BitString(Obj):
2383 """``BIT STRING`` bit string type
2385 >>> BitString(b"hello world")
2386 BIT STRING 88 bits 68656c6c6f20776f726c64
2389 >>> b == b"hello world"
2394 >>> BitString("'0A3B5F291CD'H")
2395 BIT STRING 44 bits 0a3b5f291cd0
2396 >>> b = BitString("'010110000000'B")
2397 BIT STRING 12 bits 5800
2400 >>> b[0], b[1], b[2], b[3]
2401 (False, True, False, True)
2405 [False, True, False, True, True, False, False, False, False, False, False, False]
2409 class KeyUsage(BitString):
2411 ("digitalSignature", 0),
2412 ("nonRepudiation", 1),
2413 ("keyEncipherment", 2),
2416 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2417 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2419 ['nonRepudiation', 'keyEncipherment']
2421 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2425 Pay attention that BIT STRING can be encoded both in primitive
2426 and constructed forms. Decoder always checks constructed form tag
2427 additionally to specified primitive one. If BER decoding is
2428 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2429 of DER restrictions.
2431 __slots__ = ("tag_constructed", "specs", "defined")
2432 tag_default = tag_encode(3)
2433 asn1_type_name = "BIT STRING"
2446 :param value: set the value. Either binary type, tuple of named
2447 values (if ``schema`` is specified in the class),
2448 string in ``'XXX...'B`` form, or
2449 :py:class:`pyderasn.BitString` object
2450 :param bytes impl: override default tag with ``IMPLICIT`` one
2451 :param bytes expl: override default tag with ``EXPLICIT`` one
2452 :param default: set default value. Type same as in ``value``
2453 :param bool optional: is object ``OPTIONAL`` in sequence
2455 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2456 specs = getattr(self, "schema", {}) if _specs is None else _specs
2457 self.specs = specs if specs.__class__ == dict else dict(specs)
2458 self._value = None if value is None else self._value_sanitize(value)
2459 if default is not None:
2460 default = self._value_sanitize(default)
2461 self.default = self.__class__(
2467 self._value = default
2469 tag_klass, _, tag_num = tag_decode(self.tag)
2470 self.tag_constructed = tag_encode(
2472 form=TagFormConstructed,
2476 def _bits2octets(self, bits):
2477 if len(self.specs) > 0:
2478 bits = bits.rstrip("0")
2480 bits += "0" * ((8 - (bit_len % 8)) % 8)
2481 octets = bytearray(len(bits) // 8)
2482 for i in six_xrange(len(octets)):
2483 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2484 return bit_len, bytes(octets)
2486 def _value_sanitize(self, value):
2487 if isinstance(value, (string_types, binary_type)):
2489 isinstance(value, string_types) and
2490 value.startswith("'")
2492 if value.endswith("'B"):
2494 if not frozenset(value) <= SET01:
2495 raise ValueError("B's coding contains unacceptable chars")
2496 return self._bits2octets(value)
2497 if value.endswith("'H"):
2501 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2503 if value.__class__ == binary_type:
2504 return (len(value) * 8, value)
2505 raise InvalidValueType((self.__class__, string_types, binary_type))
2506 if value.__class__ == tuple:
2509 isinstance(value[0], integer_types) and
2510 value[1].__class__ == binary_type
2515 bit = self.specs.get(name)
2517 raise ObjUnknown("BitString value: %s" % name)
2520 return self._bits2octets("")
2521 bits = frozenset(bits)
2522 return self._bits2octets("".join(
2523 ("1" if bit in bits else "0")
2524 for bit in six_xrange(max(bits) + 1)
2526 if issubclass(value.__class__, BitString):
2528 raise InvalidValueType((self.__class__, binary_type, string_types))
2532 return self._value is not None
2534 def __getstate__(self):
2535 return BitStringState(
2549 self.tag_constructed,
2553 def __setstate__(self, state):
2554 super(BitString, self).__setstate__(state)
2555 self.specs = state.specs
2556 self._value = state.value
2557 self.tag = state.tag
2558 self._expl = state.expl
2559 self.default = state.default
2560 self.optional = state.optional
2561 self.offset = state.offset
2562 self.llen = state.llen
2563 self.vlen = state.vlen
2564 self.expl_lenindef = state.expl_lenindef
2565 self.lenindef = state.lenindef
2566 self.ber_encoded = state.ber_encoded
2567 self.tag_constructed = state.tag_constructed
2568 self.defined = state.defined
2571 self._assert_ready()
2572 for i in six_xrange(self._value[0]):
2577 self._assert_ready()
2578 return self._value[0]
2580 def __bytes__(self):
2581 self._assert_ready()
2582 return self._value[1]
2584 def __eq__(self, their):
2585 if their.__class__ == bytes:
2586 return self._value[1] == their
2587 if not issubclass(their.__class__, BitString):
2590 self._value == their._value and
2591 self.tag == their.tag and
2592 self._expl == their._expl
2597 return [name for name, bit in iteritems(self.specs) if self[bit]]
2607 return self.__class__(
2609 impl=self.tag if impl is None else impl,
2610 expl=self._expl if expl is None else expl,
2611 default=self.default if default is None else default,
2612 optional=self.optional if optional is None else optional,
2616 def __getitem__(self, key):
2617 if key.__class__ == int:
2618 bit_len, octets = self._value
2622 byte2int(memoryview(octets)[key // 8:]) >>
2625 if isinstance(key, string_types):
2626 value = self.specs.get(key)
2628 raise ObjUnknown("BitString value: %s" % key)
2630 raise InvalidValueType((int, str))
2633 self._assert_ready()
2634 bit_len, octets = self._value
2637 len_encode(len(octets) + 1),
2638 int2byte((8 - bit_len % 8) % 8),
2642 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2644 t, tlen, lv = tag_strip(tlv)
2645 except DecodeError as err:
2646 raise err.__class__(
2648 klass=self.__class__,
2649 decode_path=decode_path,
2653 if tag_only: # pragma: no cover
2656 l, llen, v = len_decode(lv)
2657 except DecodeError as err:
2658 raise err.__class__(
2660 klass=self.__class__,
2661 decode_path=decode_path,
2665 raise NotEnoughData(
2666 "encoded length is longer than data",
2667 klass=self.__class__,
2668 decode_path=decode_path,
2672 raise NotEnoughData(
2674 klass=self.__class__,
2675 decode_path=decode_path,
2678 pad_size = byte2int(v)
2679 if l == 1 and pad_size != 0:
2681 "invalid empty value",
2682 klass=self.__class__,
2683 decode_path=decode_path,
2689 klass=self.__class__,
2690 decode_path=decode_path,
2693 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2696 klass=self.__class__,
2697 decode_path=decode_path,
2700 v, tail = v[:l], v[l:]
2701 obj = self.__class__(
2702 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2705 default=self.default,
2706 optional=self.optional,
2708 _decoded=(offset, llen, l),
2711 if t != self.tag_constructed:
2713 klass=self.__class__,
2714 decode_path=decode_path,
2717 if not ctx.get("bered", False):
2719 "unallowed BER constructed encoding",
2720 klass=self.__class__,
2721 decode_path=decode_path,
2724 if tag_only: # pragma: no cover
2728 l, llen, v = len_decode(lv)
2729 except LenIndefForm:
2730 llen, l, v = 1, 0, lv[1:]
2732 except DecodeError as err:
2733 raise err.__class__(
2735 klass=self.__class__,
2736 decode_path=decode_path,
2740 raise NotEnoughData(
2741 "encoded length is longer than data",
2742 klass=self.__class__,
2743 decode_path=decode_path,
2746 if not lenindef and l == 0:
2747 raise NotEnoughData(
2749 klass=self.__class__,
2750 decode_path=decode_path,
2754 sub_offset = offset + tlen + llen
2758 if v[:EOC_LEN].tobytes() == EOC:
2765 "chunk out of bounds",
2766 klass=self.__class__,
2767 decode_path=decode_path + (str(len(chunks) - 1),),
2768 offset=chunks[-1].offset,
2770 sub_decode_path = decode_path + (str(len(chunks)),)
2772 chunk, v_tail = BitString().decode(
2775 decode_path=sub_decode_path,
2778 _ctx_immutable=False,
2782 "expected BitString encoded chunk",
2783 klass=self.__class__,
2784 decode_path=sub_decode_path,
2787 chunks.append(chunk)
2788 sub_offset += chunk.tlvlen
2789 vlen += chunk.tlvlen
2791 if len(chunks) == 0:
2794 klass=self.__class__,
2795 decode_path=decode_path,
2800 for chunk_i, chunk in enumerate(chunks[:-1]):
2801 if chunk.bit_len % 8 != 0:
2803 "BitString chunk is not multiple of 8 bits",
2804 klass=self.__class__,
2805 decode_path=decode_path + (str(chunk_i),),
2806 offset=chunk.offset,
2808 values.append(bytes(chunk))
2809 bit_len += chunk.bit_len
2810 chunk_last = chunks[-1]
2811 values.append(bytes(chunk_last))
2812 bit_len += chunk_last.bit_len
2813 obj = self.__class__(
2814 value=(bit_len, b"".join(values)),
2817 default=self.default,
2818 optional=self.optional,
2820 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2822 obj.lenindef = lenindef
2823 obj.ber_encoded = True
2824 return obj, (v[EOC_LEN:] if lenindef else v)
2827 return pp_console_row(next(self.pps()))
2829 def pps(self, decode_path=()):
2833 bit_len, blob = self._value
2834 value = "%d bits" % bit_len
2835 if len(self.specs) > 0:
2836 blob = tuple(self.named)
2839 asn1_type_name=self.asn1_type_name,
2840 obj_name=self.__class__.__name__,
2841 decode_path=decode_path,
2844 optional=self.optional,
2845 default=self == self.default,
2846 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2847 expl=None if self._expl is None else tag_decode(self._expl),
2852 expl_offset=self.expl_offset if self.expled else None,
2853 expl_tlen=self.expl_tlen if self.expled else None,
2854 expl_llen=self.expl_llen if self.expled else None,
2855 expl_vlen=self.expl_vlen if self.expled else None,
2856 expl_lenindef=self.expl_lenindef,
2857 lenindef=self.lenindef,
2858 ber_encoded=self.ber_encoded,
2861 defined_by, defined = self.defined or (None, None)
2862 if defined_by is not None:
2864 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2866 for pp in self.pps_lenindef(decode_path):
2870 OctetStringState = namedtuple("OctetStringState", (
2887 ), **NAMEDTUPLE_KWARGS)
2890 class OctetString(Obj):
2891 """``OCTET STRING`` binary string type
2893 >>> s = OctetString(b"hello world")
2894 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2895 >>> s == OctetString(b"hello world")
2900 >>> OctetString(b"hello", bounds=(4, 4))
2901 Traceback (most recent call last):
2902 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2903 >>> OctetString(b"hell", bounds=(4, 4))
2904 OCTET STRING 4 bytes 68656c6c
2908 Pay attention that OCTET STRING can be encoded both in primitive
2909 and constructed forms. Decoder always checks constructed form tag
2910 additionally to specified primitive one. If BER decoding is
2911 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2912 of DER restrictions.
2914 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2915 tag_default = tag_encode(4)
2916 asn1_type_name = "OCTET STRING"
2930 :param value: set the value. Either binary type, or
2931 :py:class:`pyderasn.OctetString` object
2932 :param bounds: set ``(MIN, MAX)`` value size constraint.
2933 (-inf, +inf) by default
2934 :param bytes impl: override default tag with ``IMPLICIT`` one
2935 :param bytes expl: override default tag with ``EXPLICIT`` one
2936 :param default: set default value. Type same as in ``value``
2937 :param bool optional: is object ``OPTIONAL`` in sequence
2939 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2941 self._bound_min, self._bound_max = getattr(
2945 ) if bounds is None else bounds
2946 if value is not None:
2947 self._value = self._value_sanitize(value)
2948 if default is not None:
2949 default = self._value_sanitize(default)
2950 self.default = self.__class__(
2955 if self._value is None:
2956 self._value = default
2958 tag_klass, _, tag_num = tag_decode(self.tag)
2959 self.tag_constructed = tag_encode(
2961 form=TagFormConstructed,
2965 def _value_sanitize(self, value):
2966 if value.__class__ == binary_type:
2968 elif issubclass(value.__class__, OctetString):
2969 value = value._value
2971 raise InvalidValueType((self.__class__, bytes))
2972 if not self._bound_min <= len(value) <= self._bound_max:
2973 raise BoundsError(self._bound_min, len(value), self._bound_max)
2978 return self._value is not None
2980 def __getstate__(self):
2981 return OctetStringState(
2996 self.tag_constructed,
3000 def __setstate__(self, state):
3001 super(OctetString, self).__setstate__(state)
3002 self._value = state.value
3003 self._bound_min = state.bound_min
3004 self._bound_max = state.bound_max
3005 self.tag = state.tag
3006 self._expl = state.expl
3007 self.default = state.default
3008 self.optional = state.optional
3009 self.offset = state.offset
3010 self.llen = state.llen
3011 self.vlen = state.vlen
3012 self.expl_lenindef = state.expl_lenindef
3013 self.lenindef = state.lenindef
3014 self.ber_encoded = state.ber_encoded
3015 self.tag_constructed = state.tag_constructed
3016 self.defined = state.defined
3018 def __bytes__(self):
3019 self._assert_ready()
3022 def __eq__(self, their):
3023 if their.__class__ == binary_type:
3024 return self._value == their
3025 if not issubclass(their.__class__, OctetString):
3028 self._value == their._value and
3029 self.tag == their.tag and
3030 self._expl == their._expl
3033 def __lt__(self, their):
3034 return self._value < their._value
3045 return self.__class__(
3048 (self._bound_min, self._bound_max)
3049 if bounds is None else bounds
3051 impl=self.tag if impl is None else impl,
3052 expl=self._expl if expl is None else expl,
3053 default=self.default if default is None else default,
3054 optional=self.optional if optional is None else optional,
3058 self._assert_ready()
3061 len_encode(len(self._value)),
3065 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3067 t, tlen, lv = tag_strip(tlv)
3068 except DecodeError as err:
3069 raise err.__class__(
3071 klass=self.__class__,
3072 decode_path=decode_path,
3079 l, llen, v = len_decode(lv)
3080 except DecodeError as err:
3081 raise err.__class__(
3083 klass=self.__class__,
3084 decode_path=decode_path,
3088 raise NotEnoughData(
3089 "encoded length is longer than data",
3090 klass=self.__class__,
3091 decode_path=decode_path,
3094 v, tail = v[:l], v[l:]
3096 obj = self.__class__(
3098 bounds=(self._bound_min, self._bound_max),
3101 default=self.default,
3102 optional=self.optional,
3103 _decoded=(offset, llen, l),
3106 except DecodeError as err:
3109 klass=self.__class__,
3110 decode_path=decode_path,
3113 except BoundsError as err:
3116 klass=self.__class__,
3117 decode_path=decode_path,
3121 if t != self.tag_constructed:
3123 klass=self.__class__,
3124 decode_path=decode_path,
3127 if not ctx.get("bered", False):
3129 "unallowed BER constructed encoding",
3130 klass=self.__class__,
3131 decode_path=decode_path,
3138 l, llen, v = len_decode(lv)
3139 except LenIndefForm:
3140 llen, l, v = 1, 0, lv[1:]
3142 except DecodeError as err:
3143 raise err.__class__(
3145 klass=self.__class__,
3146 decode_path=decode_path,
3150 raise NotEnoughData(
3151 "encoded length is longer than data",
3152 klass=self.__class__,
3153 decode_path=decode_path,
3157 sub_offset = offset + tlen + llen
3161 if v[:EOC_LEN].tobytes() == EOC:
3168 "chunk out of bounds",
3169 klass=self.__class__,
3170 decode_path=decode_path + (str(len(chunks) - 1),),
3171 offset=chunks[-1].offset,
3173 sub_decode_path = decode_path + (str(len(chunks)),)
3175 chunk, v_tail = OctetString().decode(
3178 decode_path=sub_decode_path,
3181 _ctx_immutable=False,
3185 "expected OctetString encoded chunk",
3186 klass=self.__class__,
3187 decode_path=sub_decode_path,
3190 chunks.append(chunk)
3191 sub_offset += chunk.tlvlen
3192 vlen += chunk.tlvlen
3195 obj = self.__class__(
3196 value=b"".join(bytes(chunk) for chunk in chunks),
3197 bounds=(self._bound_min, self._bound_max),
3200 default=self.default,
3201 optional=self.optional,
3202 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3205 except DecodeError as err:
3208 klass=self.__class__,
3209 decode_path=decode_path,
3212 except BoundsError as err:
3215 klass=self.__class__,
3216 decode_path=decode_path,
3219 obj.lenindef = lenindef
3220 obj.ber_encoded = True
3221 return obj, (v[EOC_LEN:] if lenindef else v)
3224 return pp_console_row(next(self.pps()))
3226 def pps(self, decode_path=()):
3229 asn1_type_name=self.asn1_type_name,
3230 obj_name=self.__class__.__name__,
3231 decode_path=decode_path,
3232 value=("%d bytes" % len(self._value)) if self.ready else None,
3233 blob=self._value if self.ready else None,
3234 optional=self.optional,
3235 default=self == self.default,
3236 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3237 expl=None if self._expl is None else tag_decode(self._expl),
3242 expl_offset=self.expl_offset if self.expled else None,
3243 expl_tlen=self.expl_tlen if self.expled else None,
3244 expl_llen=self.expl_llen if self.expled else None,
3245 expl_vlen=self.expl_vlen if self.expled else None,
3246 expl_lenindef=self.expl_lenindef,
3247 lenindef=self.lenindef,
3248 ber_encoded=self.ber_encoded,
3251 defined_by, defined = self.defined or (None, None)
3252 if defined_by is not None:
3254 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3256 for pp in self.pps_lenindef(decode_path):
3260 NullState = namedtuple("NullState", (
3272 ), **NAMEDTUPLE_KWARGS)
3276 """``NULL`` null object
3284 tag_default = tag_encode(5)
3285 asn1_type_name = "NULL"
3289 value=None, # unused, but Sequence passes it
3296 :param bytes impl: override default tag with ``IMPLICIT`` one
3297 :param bytes expl: override default tag with ``EXPLICIT`` one
3298 :param bool optional: is object ``OPTIONAL`` in sequence
3300 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3307 def __getstate__(self):
3322 def __setstate__(self, state):
3323 super(Null, self).__setstate__(state)
3324 self.tag = state.tag
3325 self._expl = state.expl
3326 self.default = state.default
3327 self.optional = state.optional
3328 self.offset = state.offset
3329 self.llen = state.llen
3330 self.vlen = state.vlen
3331 self.expl_lenindef = state.expl_lenindef
3332 self.lenindef = state.lenindef
3333 self.ber_encoded = state.ber_encoded
3335 def __eq__(self, their):
3336 if not issubclass(their.__class__, Null):
3339 self.tag == their.tag and
3340 self._expl == their._expl
3350 return self.__class__(
3351 impl=self.tag if impl is None else impl,
3352 expl=self._expl if expl is None else expl,
3353 optional=self.optional if optional is None else optional,
3357 return self.tag + len_encode(0)
3359 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3361 t, _, lv = tag_strip(tlv)
3362 except DecodeError as err:
3363 raise err.__class__(
3365 klass=self.__class__,
3366 decode_path=decode_path,
3371 klass=self.__class__,
3372 decode_path=decode_path,
3375 if tag_only: # pragma: no cover
3378 l, _, v = len_decode(lv)
3379 except DecodeError as err:
3380 raise err.__class__(
3382 klass=self.__class__,
3383 decode_path=decode_path,
3387 raise InvalidLength(
3388 "Null must have zero length",
3389 klass=self.__class__,
3390 decode_path=decode_path,
3393 obj = self.__class__(
3396 optional=self.optional,
3397 _decoded=(offset, 1, 0),
3402 return pp_console_row(next(self.pps()))
3404 def pps(self, decode_path=()):
3407 asn1_type_name=self.asn1_type_name,
3408 obj_name=self.__class__.__name__,
3409 decode_path=decode_path,
3410 optional=self.optional,
3411 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3412 expl=None if self._expl is None else tag_decode(self._expl),
3417 expl_offset=self.expl_offset if self.expled else None,
3418 expl_tlen=self.expl_tlen if self.expled else None,
3419 expl_llen=self.expl_llen if self.expled else None,
3420 expl_vlen=self.expl_vlen if self.expled else None,
3421 expl_lenindef=self.expl_lenindef,
3424 for pp in self.pps_lenindef(decode_path):
3428 ObjectIdentifierState = namedtuple("ObjectIdentifierState", (
3442 ), **NAMEDTUPLE_KWARGS)
3445 class ObjectIdentifier(Obj):
3446 """``OBJECT IDENTIFIER`` OID type
3448 >>> oid = ObjectIdentifier((1, 2, 3))
3449 OBJECT IDENTIFIER 1.2.3
3450 >>> oid == ObjectIdentifier("1.2.3")
3456 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3457 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3459 >>> str(ObjectIdentifier((3, 1)))
3460 Traceback (most recent call last):
3461 pyderasn.InvalidOID: unacceptable first arc value
3463 __slots__ = ("defines",)
3464 tag_default = tag_encode(6)
3465 asn1_type_name = "OBJECT IDENTIFIER"
3478 :param value: set the value. Either tuples of integers,
3479 string of "."-concatenated integers, or
3480 :py:class:`pyderasn.ObjectIdentifier` object
3481 :param defines: sequence of tuples. Each tuple has two elements.
3482 First one is relative to current one decode
3483 path, aiming to the field defined by that OID.
3484 Read about relative path in
3485 :py:func:`pyderasn.abs_decode_path`. Second
3486 tuple element is ``{OID: pyderasn.Obj()}``
3487 dictionary, mapping between current OID value
3488 and structure applied to defined field.
3489 :ref:`Read about DEFINED BY <definedby>`
3490 :param bytes impl: override default tag with ``IMPLICIT`` one
3491 :param bytes expl: override default tag with ``EXPLICIT`` one
3492 :param default: set default value. Type same as in ``value``
3493 :param bool optional: is object ``OPTIONAL`` in sequence
3495 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3497 if value is not None:
3498 self._value = self._value_sanitize(value)
3499 if default is not None:
3500 default = self._value_sanitize(default)
3501 self.default = self.__class__(
3506 if self._value is None:
3507 self._value = default
3508 self.defines = defines
3510 def __add__(self, their):
3511 if their.__class__ == tuple:
3512 return self.__class__(self._value + their)
3513 if isinstance(their, self.__class__):
3514 return self.__class__(self._value + their._value)
3515 raise InvalidValueType((self.__class__, tuple))
3517 def _value_sanitize(self, value):
3518 if issubclass(value.__class__, ObjectIdentifier):
3520 if isinstance(value, string_types):
3522 value = tuple(pureint(arc) for arc in value.split("."))
3524 raise InvalidOID("unacceptable arcs values")
3525 if value.__class__ == tuple:
3527 raise InvalidOID("less than 2 arcs")
3528 first_arc = value[0]
3529 if first_arc in (0, 1):
3530 if not (0 <= value[1] <= 39):
3531 raise InvalidOID("second arc is too wide")
3532 elif first_arc == 2:
3535 raise InvalidOID("unacceptable first arc value")
3536 if not all(arc >= 0 for arc in value):
3537 raise InvalidOID("negative arc value")
3539 raise InvalidValueType((self.__class__, str, tuple))
3543 return self._value is not None
3545 def __getstate__(self):
3546 return ObjectIdentifierState(
3562 def __setstate__(self, state):
3563 super(ObjectIdentifier, self).__setstate__(state)
3564 self._value = state.value
3565 self.tag = state.tag
3566 self._expl = state.expl
3567 self.default = state.default
3568 self.optional = state.optional
3569 self.offset = state.offset
3570 self.llen = state.llen
3571 self.vlen = state.vlen
3572 self.expl_lenindef = state.expl_lenindef
3573 self.lenindef = state.lenindef
3574 self.ber_encoded = state.ber_encoded
3575 self.defines = state.defines
3578 self._assert_ready()
3579 return iter(self._value)
3582 return ".".join(str(arc) for arc in self._value or ())
3585 self._assert_ready()
3588 bytes(self._expl or b"") +
3589 str(self._value).encode("ascii"),
3592 def __eq__(self, their):
3593 if their.__class__ == tuple:
3594 return self._value == their
3595 if not issubclass(their.__class__, ObjectIdentifier):
3598 self.tag == their.tag and
3599 self._expl == their._expl and
3600 self._value == their._value
3603 def __lt__(self, their):
3604 return self._value < their._value
3615 return self.__class__(
3617 defines=self.defines if defines is None else defines,
3618 impl=self.tag if impl is None else impl,
3619 expl=self._expl if expl is None else expl,
3620 default=self.default if default is None else default,
3621 optional=self.optional if optional is None else optional,
3625 self._assert_ready()
3627 first_value = value[1]
3628 first_arc = value[0]
3631 elif first_arc == 1:
3633 elif first_arc == 2:
3635 else: # pragma: no cover
3636 raise RuntimeError("invalid arc is stored")
3637 octets = [zero_ended_encode(first_value)]
3638 for arc in value[2:]:
3639 octets.append(zero_ended_encode(arc))
3640 v = b"".join(octets)
3641 return b"".join((self.tag, len_encode(len(v)), v))
3643 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3645 t, _, lv = tag_strip(tlv)
3646 except DecodeError as err:
3647 raise err.__class__(
3649 klass=self.__class__,
3650 decode_path=decode_path,
3655 klass=self.__class__,
3656 decode_path=decode_path,
3659 if tag_only: # pragma: no cover
3662 l, llen, v = len_decode(lv)
3663 except DecodeError as err:
3664 raise err.__class__(
3666 klass=self.__class__,
3667 decode_path=decode_path,
3671 raise NotEnoughData(
3672 "encoded length is longer than data",
3673 klass=self.__class__,
3674 decode_path=decode_path,
3678 raise NotEnoughData(
3680 klass=self.__class__,
3681 decode_path=decode_path,
3684 v, tail = v[:l], v[l:]
3691 octet = indexbytes(v, i)
3692 if i == 0 and octet == 0x80:
3693 if ctx.get("bered", False):
3696 raise DecodeError("non normalized arc encoding")
3697 arc = (arc << 7) | (octet & 0x7F)
3698 if octet & 0x80 == 0:
3706 klass=self.__class__,
3707 decode_path=decode_path,
3711 second_arc = arcs[0]
3712 if 0 <= second_arc <= 39:
3714 elif 40 <= second_arc <= 79:
3720 obj = self.__class__(
3721 value=tuple([first_arc, second_arc] + arcs[1:]),
3724 default=self.default,
3725 optional=self.optional,
3726 _decoded=(offset, llen, l),
3729 obj.ber_encoded = True
3733 return pp_console_row(next(self.pps()))
3735 def pps(self, decode_path=()):
3738 asn1_type_name=self.asn1_type_name,
3739 obj_name=self.__class__.__name__,
3740 decode_path=decode_path,
3741 value=str(self) if self.ready else None,
3742 optional=self.optional,
3743 default=self == self.default,
3744 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3745 expl=None if self._expl is None else tag_decode(self._expl),
3750 expl_offset=self.expl_offset if self.expled else None,
3751 expl_tlen=self.expl_tlen if self.expled else None,
3752 expl_llen=self.expl_llen if self.expled else None,
3753 expl_vlen=self.expl_vlen if self.expled else None,
3754 expl_lenindef=self.expl_lenindef,
3755 ber_encoded=self.ber_encoded,
3758 for pp in self.pps_lenindef(decode_path):
3762 class Enumerated(Integer):
3763 """``ENUMERATED`` integer type
3765 This type is identical to :py:class:`pyderasn.Integer`, but requires
3766 schema to be specified and does not accept values missing from it.
3769 tag_default = tag_encode(10)
3770 asn1_type_name = "ENUMERATED"
3781 bounds=None, # dummy argument, workability for Integer.decode
3783 super(Enumerated, self).__init__(
3784 value, bounds, impl, expl, default, optional, _specs, _decoded,
3786 if len(self.specs) == 0:
3787 raise ValueError("schema must be specified")
3789 def _value_sanitize(self, value):
3790 if isinstance(value, self.__class__):
3791 value = value._value
3792 elif isinstance(value, integer_types):
3793 for _value in itervalues(self.specs):
3798 "unknown integer value: %s" % value,
3799 klass=self.__class__,
3801 elif isinstance(value, string_types):
3802 value = self.specs.get(value)
3804 raise ObjUnknown("integer value: %s" % value)
3806 raise InvalidValueType((self.__class__, int, str))
3818 return self.__class__(
3820 impl=self.tag if impl is None else impl,
3821 expl=self._expl if expl is None else expl,
3822 default=self.default if default is None else default,
3823 optional=self.optional if optional is None else optional,
3828 def escape_control_unicode(c):
3829 if unicat(c)[0] == "C":
3830 c = repr(c).lstrip("u").strip("'")
3834 class CommonString(OctetString):
3835 """Common class for all strings
3837 Everything resembles :py:class:`pyderasn.OctetString`, except
3838 ability to deal with unicode text strings.
3840 >>> hexenc("привет мир".encode("utf-8"))
3841 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3842 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3844 >>> s = UTF8String("привет мир")
3845 UTF8String UTF8String привет мир
3847 'привет мир'
3848 >>> hexenc(bytes(s))
3849 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3851 >>> PrintableString("привет мир")
3852 Traceback (most recent call last):
3853 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3855 >>> BMPString("ада", bounds=(2, 2))
3856 Traceback (most recent call last):
3857 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3858 >>> s = BMPString("ад", bounds=(2, 2))
3861 >>> hexenc(bytes(s))
3869 * - :py:class:`pyderasn.UTF8String`
3871 * - :py:class:`pyderasn.NumericString`
3873 * - :py:class:`pyderasn.PrintableString`
3875 * - :py:class:`pyderasn.TeletexString`
3877 * - :py:class:`pyderasn.T61String`
3879 * - :py:class:`pyderasn.VideotexString`
3881 * - :py:class:`pyderasn.IA5String`
3883 * - :py:class:`pyderasn.GraphicString`
3885 * - :py:class:`pyderasn.VisibleString`
3887 * - :py:class:`pyderasn.ISO646String`
3889 * - :py:class:`pyderasn.GeneralString`
3891 * - :py:class:`pyderasn.UniversalString`
3893 * - :py:class:`pyderasn.BMPString`
3898 def _value_sanitize(self, value):
3900 value_decoded = None
3901 if isinstance(value, self.__class__):
3902 value_raw = value._value
3903 elif value.__class__ == text_type:
3904 value_decoded = value
3905 elif value.__class__ == binary_type:
3908 raise InvalidValueType((self.__class__, text_type, binary_type))
3911 value_decoded.encode(self.encoding)
3912 if value_raw is None else value_raw
3915 value_raw.decode(self.encoding)
3916 if value_decoded is None else value_decoded
3918 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3919 raise DecodeError(str(err))
3920 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3928 def __eq__(self, their):
3929 if their.__class__ == binary_type:
3930 return self._value == their
3931 if their.__class__ == text_type:
3932 return self._value == their.encode(self.encoding)
3933 if not isinstance(their, self.__class__):
3936 self._value == their._value and
3937 self.tag == their.tag and
3938 self._expl == their._expl
3941 def __unicode__(self):
3943 return self._value.decode(self.encoding)
3944 return text_type(self._value)
3947 return pp_console_row(next(self.pps(no_unicode=PY2)))
3949 def pps(self, decode_path=(), no_unicode=False):
3953 hexenc(bytes(self)) if no_unicode else
3954 "".join(escape_control_unicode(c) for c in self.__unicode__())
3958 asn1_type_name=self.asn1_type_name,
3959 obj_name=self.__class__.__name__,
3960 decode_path=decode_path,
3962 optional=self.optional,
3963 default=self == self.default,
3964 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3965 expl=None if self._expl is None else tag_decode(self._expl),
3970 expl_offset=self.expl_offset if self.expled else None,
3971 expl_tlen=self.expl_tlen if self.expled else None,
3972 expl_llen=self.expl_llen if self.expled else None,
3973 expl_vlen=self.expl_vlen if self.expled else None,
3974 expl_lenindef=self.expl_lenindef,
3975 ber_encoded=self.ber_encoded,
3978 for pp in self.pps_lenindef(decode_path):
3982 class UTF8String(CommonString):
3984 tag_default = tag_encode(12)
3986 asn1_type_name = "UTF8String"
3989 class AllowableCharsMixin(object):
3991 def allowable_chars(self):
3993 return self._allowable_chars
3994 return frozenset(six_unichr(c) for c in self._allowable_chars)
3997 class NumericString(AllowableCharsMixin, CommonString):
4000 Its value is properly sanitized: only ASCII digits with spaces can
4003 >>> NumericString().allowable_chars
4004 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
4007 tag_default = tag_encode(18)
4009 asn1_type_name = "NumericString"
4010 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
4012 def _value_sanitize(self, value):
4013 value = super(NumericString, self)._value_sanitize(value)
4014 if not frozenset(value) <= self._allowable_chars:
4015 raise DecodeError("non-numeric value")
4019 PrintableStringState = namedtuple(
4020 "PrintableStringState",
4021 OctetStringState._fields + ("allowable_chars",),
4026 class PrintableString(AllowableCharsMixin, CommonString):
4029 Its value is properly sanitized: see X.680 41.4 table 10.
4031 >>> PrintableString().allowable_chars
4032 frozenset([' ', "'", ..., 'z'])
4033 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4034 PrintableString PrintableString foo*bar
4035 >>> obj.allow_asterisk, obj.allow_ampersand
4039 tag_default = tag_encode(19)
4041 asn1_type_name = "PrintableString"
4042 _allowable_chars = frozenset(
4043 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4045 _asterisk = frozenset("*".encode("ascii"))
4046 _ampersand = frozenset("&".encode("ascii"))
4058 allow_asterisk=False,
4059 allow_ampersand=False,
4062 :param allow_asterisk: allow asterisk character
4063 :param allow_ampersand: allow ampersand character
4066 self._allowable_chars |= self._asterisk
4068 self._allowable_chars |= self._ampersand
4069 super(PrintableString, self).__init__(
4070 value, bounds, impl, expl, default, optional, _decoded, ctx,
4074 def allow_asterisk(self):
4075 """Is asterisk character allowed?
4077 return self._asterisk <= self._allowable_chars
4080 def allow_ampersand(self):
4081 """Is ampersand character allowed?
4083 return self._ampersand <= self._allowable_chars
4085 def _value_sanitize(self, value):
4086 value = super(PrintableString, self)._value_sanitize(value)
4087 if not frozenset(value) <= self._allowable_chars:
4088 raise DecodeError("non-printable value")
4091 def __getstate__(self):
4092 return PrintableStringState(
4093 *super(PrintableString, self).__getstate__(),
4094 **{"allowable_chars": self._allowable_chars}
4097 def __setstate__(self, state):
4098 super(PrintableString, self).__setstate__(state)
4099 self._allowable_chars = state.allowable_chars
4110 return self.__class__(
4113 (self._bound_min, self._bound_max)
4114 if bounds is None else bounds
4116 impl=self.tag if impl is None else impl,
4117 expl=self._expl if expl is None else expl,
4118 default=self.default if default is None else default,
4119 optional=self.optional if optional is None else optional,
4120 allow_asterisk=self.allow_asterisk,
4121 allow_ampersand=self.allow_ampersand,
4125 class TeletexString(CommonString):
4127 tag_default = tag_encode(20)
4129 asn1_type_name = "TeletexString"
4132 class T61String(TeletexString):
4134 asn1_type_name = "T61String"
4137 class VideotexString(CommonString):
4139 tag_default = tag_encode(21)
4140 encoding = "iso-8859-1"
4141 asn1_type_name = "VideotexString"
4144 class IA5String(CommonString):
4146 tag_default = tag_encode(22)
4148 asn1_type_name = "IA5"
4151 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4152 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4153 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4156 class VisibleString(CommonString):
4158 tag_default = tag_encode(26)
4160 asn1_type_name = "VisibleString"
4163 UTCTimeState = namedtuple(
4165 OctetStringState._fields + ("ber_raw",),
4170 def str_to_time_fractions(value):
4172 year, v = (v // 10**10), (v % 10**10)
4173 month, v = (v // 10**8), (v % 10**8)
4174 day, v = (v // 10**6), (v % 10**6)
4175 hour, v = (v // 10**4), (v % 10**4)
4176 minute, second = (v // 100), (v % 100)
4177 return year, month, day, hour, minute, second
4180 class UTCTime(VisibleString):
4181 """``UTCTime`` datetime type
4183 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4184 UTCTime UTCTime 2017-09-30T22:07:50
4190 datetime.datetime(2017, 9, 30, 22, 7, 50)
4191 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4192 datetime.datetime(1957, 9, 30, 22, 7, 50)
4194 If BER encoded value was met, then ``ber_raw`` attribute will hold
4195 its raw representation.
4199 Pay attention that UTCTime can not hold full year, so all years
4200 having < 50 years are treated as 20xx, 19xx otherwise, according
4201 to X.509 recommendation.
4205 No strict validation of UTC offsets are made, but very crude:
4207 * minutes are not exceeding 60
4208 * offset value is not exceeding 14 hours
4210 __slots__ = ("ber_raw",)
4211 tag_default = tag_encode(23)
4213 asn1_type_name = "UTCTime"
4223 bounds=None, # dummy argument, workability for OctetString.decode
4227 :param value: set the value. Either datetime type, or
4228 :py:class:`pyderasn.UTCTime` object
4229 :param bytes impl: override default tag with ``IMPLICIT`` one
4230 :param bytes expl: override default tag with ``EXPLICIT`` one
4231 :param default: set default value. Type same as in ``value``
4232 :param bool optional: is object ``OPTIONAL`` in sequence
4234 super(UTCTime, self).__init__(
4235 None, None, impl, expl, None, optional, _decoded, ctx,
4239 if value is not None:
4240 self._value, self.ber_raw = self._value_sanitize(value, ctx)
4241 self.ber_encoded = self.ber_raw is not None
4242 if default is not None:
4243 default, _ = self._value_sanitize(default)
4244 self.default = self.__class__(
4249 if self._value is None:
4250 self._value = default
4252 self.optional = optional
4254 def _strptime_bered(self, value):
4255 year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
4258 raise ValueError("no timezone")
4259 year += 2000 if year < 50 else 1900
4260 decoded = datetime(year, month, day, hour, minute)
4262 if value[-1] == "Z":
4266 raise ValueError("invalid UTC offset")
4267 if value[-5] == "-":
4269 elif value[-5] == "+":
4272 raise ValueError("invalid UTC offset")
4273 v = pureint(value[-4:])
4274 offset, v = (60 * (v % 100)), v // 100
4276 raise ValueError("invalid UTC offset minutes")
4278 if offset > 14 * 3600:
4279 raise ValueError("too big UTC offset")
4283 return offset, decoded
4285 raise ValueError("invalid UTC offset seconds")
4286 seconds = pureint(value)
4288 raise ValueError("invalid seconds value")
4289 return offset, decoded + timedelta(seconds=seconds)
4291 def _strptime(self, value):
4292 # datetime.strptime's format: %y%m%d%H%M%SZ
4293 if len(value) != LEN_YYMMDDHHMMSSZ:
4294 raise ValueError("invalid UTCTime length")
4295 if value[-1] != "Z":
4296 raise ValueError("non UTC timezone")
4297 year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
4298 year += 2000 if year < 50 else 1900
4299 return datetime(year, month, day, hour, minute, second)
4301 def _dt_sanitize(self, value):
4302 if value.year < 1950 or value.year > 2049:
4303 raise ValueError("UTCTime can hold only 1950-2049 years")
4304 return value.replace(microsecond=0)
4306 def _value_sanitize(self, value, ctx=None):
4307 if value.__class__ == binary_type:
4309 value_decoded = value.decode("ascii")
4310 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4311 raise DecodeError("invalid UTCTime encoding: %r" % err)
4314 return self._strptime(value_decoded), None
4315 except (TypeError, ValueError) as _err:
4317 if (ctx is not None) and ctx.get("bered", False):
4319 offset, _value = self._strptime_bered(value_decoded)
4320 _value = _value - timedelta(seconds=offset)
4321 return self._dt_sanitize(_value), value
4322 except (TypeError, ValueError, OverflowError) as _err:
4325 "invalid %s format: %r" % (self.asn1_type_name, err),
4326 klass=self.__class__,
4328 if isinstance(value, self.__class__):
4329 return value._value, None
4330 if value.__class__ == datetime:
4331 return self._dt_sanitize(value), None
4332 raise InvalidValueType((self.__class__, datetime))
4334 def _pp_value(self):
4336 value = self._value.isoformat()
4337 if self.ber_encoded:
4338 value += " (%s)" % self.ber_raw
4341 def __unicode__(self):
4343 value = self._value.isoformat()
4344 if self.ber_encoded:
4345 value += " (%s)" % self.ber_raw
4347 return text_type(self._pp_value())
4349 def __getstate__(self):
4350 return UTCTimeState(
4351 *super(UTCTime, self).__getstate__(),
4352 **{"ber_raw": self.ber_raw}
4355 def __setstate__(self, state):
4356 super(UTCTime, self).__setstate__(state)
4357 self.ber_raw = state.ber_raw
4359 def __bytes__(self):
4360 self._assert_ready()
4361 return self._encode_time()
4363 def __eq__(self, their):
4364 if their.__class__ == binary_type:
4365 return self._encode_time() == their
4366 if their.__class__ == datetime:
4367 return self.todatetime() == their
4368 if not isinstance(their, self.__class__):
4371 self._value == their._value and
4372 self.tag == their.tag and
4373 self._expl == their._expl
4376 def _encode_time(self):
4377 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4380 self._assert_ready()
4381 value = self._encode_time()
4382 return b"".join((self.tag, len_encode(len(value)), value))
4384 def todatetime(self):
4388 return pp_console_row(next(self.pps()))
4390 def pps(self, decode_path=()):
4393 asn1_type_name=self.asn1_type_name,
4394 obj_name=self.__class__.__name__,
4395 decode_path=decode_path,
4396 value=self._pp_value(),
4397 optional=self.optional,
4398 default=self == self.default,
4399 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4400 expl=None if self._expl is None else tag_decode(self._expl),
4405 expl_offset=self.expl_offset if self.expled else None,
4406 expl_tlen=self.expl_tlen if self.expled else None,
4407 expl_llen=self.expl_llen if self.expled else None,
4408 expl_vlen=self.expl_vlen if self.expled else None,
4409 expl_lenindef=self.expl_lenindef,
4410 ber_encoded=self.ber_encoded,
4413 for pp in self.pps_lenindef(decode_path):
4417 class GeneralizedTime(UTCTime):
4418 """``GeneralizedTime`` datetime type
4420 This type is similar to :py:class:`pyderasn.UTCTime`.
4422 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4423 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4425 '20170930220750.000123Z'
4426 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4427 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4431 Only microsecond fractions are supported in DER encoding.
4432 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4433 higher precision values.
4437 BER encoded data can loss information (accuracy) during decoding
4438 because of float transformations.
4442 Local times (without explicit timezone specification) are treated
4443 as UTC one, no transformations are made.
4447 Zero year is unsupported.
4450 tag_default = tag_encode(24)
4451 asn1_type_name = "GeneralizedTime"
4453 def _dt_sanitize(self, value):
4456 def _strptime_bered(self, value):
4457 if len(value) < 4 + 3 * 2:
4458 raise ValueError("invalid GeneralizedTime")
4459 year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
4460 decoded = datetime(year, month, day, hour)
4461 offset, value = 0, value[10:]
4463 return offset, decoded
4464 if value[-1] == "Z":
4467 for char, sign in (("-", -1), ("+", 1)):
4468 idx = value.rfind(char)
4471 offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
4472 v = pureint(offset_raw)
4473 if len(offset_raw) == 4:
4474 offset, v = (60 * (v % 100)), v // 100
4476 raise ValueError("invalid UTC offset minutes")
4477 elif len(offset_raw) == 2:
4480 raise ValueError("invalid UTC offset")
4482 if offset > 14 * 3600:
4483 raise ValueError("too big UTC offset")
4487 return offset, decoded
4488 if value[0] in DECIMAL_SIGNS:
4490 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4493 raise ValueError("stripped minutes")
4494 decoded += timedelta(seconds=60 * pureint(value[:2]))
4497 return offset, decoded
4498 if value[0] in DECIMAL_SIGNS:
4500 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4503 raise ValueError("stripped seconds")
4504 decoded += timedelta(seconds=pureint(value[:2]))
4507 return offset, decoded
4508 if value[0] not in DECIMAL_SIGNS:
4509 raise ValueError("invalid format after seconds")
4511 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4514 def _strptime(self, value):
4516 if l == LEN_YYYYMMDDHHMMSSZ:
4517 # datetime.strptime's format: %Y%m%d%H%M%SZ
4518 if value[-1] != "Z":
4519 raise ValueError("non UTC timezone")
4520 return datetime(*str_to_time_fractions(value[:-1]))
4521 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4522 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4523 if value[-1] != "Z":
4524 raise ValueError("non UTC timezone")
4525 if value[14] != ".":
4526 raise ValueError("no fractions separator")
4529 raise ValueError("trailing zero")
4532 raise ValueError("only microsecond fractions are supported")
4533 us = pureint(us + ("0" * (6 - us_len)))
4534 year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
4535 return datetime(year, month, day, hour, minute, second, us)
4536 raise ValueError("invalid GeneralizedTime length")
4538 def _encode_time(self):
4540 encoded = value.strftime("%Y%m%d%H%M%S")
4541 if value.microsecond > 0:
4542 encoded += (".%06d" % value.microsecond).rstrip("0")
4543 return (encoded + "Z").encode("ascii")
4546 class GraphicString(CommonString):
4548 tag_default = tag_encode(25)
4549 encoding = "iso-8859-1"
4550 asn1_type_name = "GraphicString"
4553 class ISO646String(VisibleString):
4555 asn1_type_name = "ISO646String"
4558 class GeneralString(CommonString):
4560 tag_default = tag_encode(27)
4561 encoding = "iso-8859-1"
4562 asn1_type_name = "GeneralString"
4565 class UniversalString(CommonString):
4567 tag_default = tag_encode(28)
4568 encoding = "utf-32-be"
4569 asn1_type_name = "UniversalString"
4572 class BMPString(CommonString):
4574 tag_default = tag_encode(30)
4575 encoding = "utf-16-be"
4576 asn1_type_name = "BMPString"
4579 ChoiceState = namedtuple("ChoiceState", (
4593 ), **NAMEDTUPLE_KWARGS)
4597 """``CHOICE`` special type
4601 class GeneralName(Choice):
4603 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4604 ("dNSName", IA5String(impl=tag_ctxp(2))),
4607 >>> gn = GeneralName()
4609 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4610 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4611 >>> gn["dNSName"] = IA5String("bar.baz")
4612 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4613 >>> gn["rfc822Name"]
4616 [2] IA5String IA5 bar.baz
4619 >>> gn.value == gn["dNSName"]
4622 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4624 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4625 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4627 __slots__ = ("specs",)
4629 asn1_type_name = "CHOICE"
4642 :param value: set the value. Either ``(choice, value)`` tuple, or
4643 :py:class:`pyderasn.Choice` object
4644 :param bytes impl: can not be set, do **not** use it
4645 :param bytes expl: override default tag with ``EXPLICIT`` one
4646 :param default: set default value. Type same as in ``value``
4647 :param bool optional: is object ``OPTIONAL`` in sequence
4649 if impl is not None:
4650 raise ValueError("no implicit tag allowed for CHOICE")
4651 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4653 schema = getattr(self, "schema", ())
4654 if len(schema) == 0:
4655 raise ValueError("schema must be specified")
4657 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
4660 if value is not None:
4661 self._value = self._value_sanitize(value)
4662 if default is not None:
4663 default_value = self._value_sanitize(default)
4664 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4665 default_obj.specs = self.specs
4666 default_obj._value = default_value
4667 self.default = default_obj
4669 self._value = copy(default_obj._value)
4671 def _value_sanitize(self, value):
4672 if (value.__class__ == tuple) and len(value) == 2:
4674 spec = self.specs.get(choice)
4676 raise ObjUnknown(choice)
4677 if not isinstance(obj, spec.__class__):
4678 raise InvalidValueType((spec,))
4679 return (choice, spec(obj))
4680 if isinstance(value, self.__class__):
4682 raise InvalidValueType((self.__class__, tuple))
4686 return self._value is not None and self._value[1].ready
4690 return self.expl_lenindef or (
4691 (self._value is not None) and
4692 self._value[1].bered
4695 def __getstate__(self):
4712 def __setstate__(self, state):
4713 super(Choice, self).__setstate__(state)
4714 self.specs = state.specs
4715 self._value = state.value
4716 self._expl = state.expl
4717 self.default = state.default
4718 self.optional = state.optional
4719 self.offset = state.offset
4720 self.llen = state.llen
4721 self.vlen = state.vlen
4722 self.expl_lenindef = state.expl_lenindef
4723 self.lenindef = state.lenindef
4724 self.ber_encoded = state.ber_encoded
4726 def __eq__(self, their):
4727 if (their.__class__ == tuple) and len(their) == 2:
4728 return self._value == their
4729 if not isinstance(their, self.__class__):
4732 self.specs == their.specs and
4733 self._value == their._value
4743 return self.__class__(
4746 expl=self._expl if expl is None else expl,
4747 default=self.default if default is None else default,
4748 optional=self.optional if optional is None else optional,
4753 self._assert_ready()
4754 return self._value[0]
4758 self._assert_ready()
4759 return self._value[1]
4761 def __getitem__(self, key):
4762 if key not in self.specs:
4763 raise ObjUnknown(key)
4764 if self._value is None:
4766 choice, value = self._value
4771 def __setitem__(self, key, value):
4772 spec = self.specs.get(key)
4774 raise ObjUnknown(key)
4775 if not isinstance(value, spec.__class__):
4776 raise InvalidValueType((spec.__class__,))
4777 self._value = (key, spec(value))
4785 return self._value[1].decoded if self.ready else False
4788 self._assert_ready()
4789 return self._value[1].encode()
4791 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4792 for choice, spec in iteritems(self.specs):
4793 sub_decode_path = decode_path + (choice,)
4799 decode_path=sub_decode_path,
4802 _ctx_immutable=False,
4809 klass=self.__class__,
4810 decode_path=decode_path,
4813 if tag_only: # pragma: no cover
4815 value, tail = spec.decode(
4819 decode_path=sub_decode_path,
4821 _ctx_immutable=False,
4823 obj = self.__class__(
4826 default=self.default,
4827 optional=self.optional,
4828 _decoded=(offset, 0, value.fulllen),
4830 obj._value = (choice, value)
4834 value = pp_console_row(next(self.pps()))
4836 value = "%s[%r]" % (value, self.value)
4839 def pps(self, decode_path=()):
4842 asn1_type_name=self.asn1_type_name,
4843 obj_name=self.__class__.__name__,
4844 decode_path=decode_path,
4845 value=self.choice if self.ready else None,
4846 optional=self.optional,
4847 default=self == self.default,
4848 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4849 expl=None if self._expl is None else tag_decode(self._expl),
4854 expl_lenindef=self.expl_lenindef,
4858 yield self.value.pps(decode_path=decode_path + (self.choice,))
4859 for pp in self.pps_lenindef(decode_path):
4863 class PrimitiveTypes(Choice):
4864 """Predefined ``CHOICE`` for all generic primitive types
4866 It could be useful for general decoding of some unspecified values:
4868 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4869 OCTET STRING 3 bytes 666f6f
4870 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4874 schema = tuple((klass.__name__, klass()) for klass in (
4898 AnyState = namedtuple("AnyState", (
4911 ), **NAMEDTUPLE_KWARGS)
4915 """``ANY`` special type
4917 >>> Any(Integer(-123))
4919 >>> a = Any(OctetString(b"hello world").encode())
4920 ANY 040b68656c6c6f20776f726c64
4921 >>> hexenc(bytes(a))
4922 b'0x040x0bhello world'
4924 __slots__ = ("defined",)
4925 tag_default = tag_encode(0)
4926 asn1_type_name = "ANY"
4936 :param value: set the value. Either any kind of pyderasn's
4937 **ready** object, or bytes. Pay attention that
4938 **no** validation is performed is raw binary value
4940 :param bytes expl: override default tag with ``EXPLICIT`` one
4941 :param bool optional: is object ``OPTIONAL`` in sequence
4943 super(Any, self).__init__(None, expl, None, optional, _decoded)
4944 self._value = None if value is None else self._value_sanitize(value)
4947 def _value_sanitize(self, value):
4948 if value.__class__ == binary_type:
4950 if isinstance(value, self.__class__):
4952 if isinstance(value, Obj):
4953 return value.encode()
4954 raise InvalidValueType((self.__class__, Obj, binary_type))
4958 return self._value is not None
4962 if self.expl_lenindef or self.lenindef:
4964 if self.defined is None:
4966 return self.defined[1].bered
4968 def __getstate__(self):
4984 def __setstate__(self, state):
4985 super(Any, self).__setstate__(state)
4986 self._value = state.value
4987 self.tag = state.tag
4988 self._expl = state.expl
4989 self.optional = state.optional
4990 self.offset = state.offset
4991 self.llen = state.llen
4992 self.vlen = state.vlen
4993 self.expl_lenindef = state.expl_lenindef
4994 self.lenindef = state.lenindef
4995 self.ber_encoded = state.ber_encoded
4996 self.defined = state.defined
4998 def __eq__(self, their):
4999 if their.__class__ == binary_type:
5000 return self._value == their
5001 if issubclass(their.__class__, Any):
5002 return self._value == their._value
5011 return self.__class__(
5013 expl=self._expl if expl is None else expl,
5014 optional=self.optional if optional is None else optional,
5017 def __bytes__(self):
5018 self._assert_ready()
5026 self._assert_ready()
5029 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5031 t, tlen, lv = tag_strip(tlv)
5032 except DecodeError as err:
5033 raise err.__class__(
5035 klass=self.__class__,
5036 decode_path=decode_path,
5040 l, llen, v = len_decode(lv)
5041 except LenIndefForm as err:
5042 if not ctx.get("bered", False):
5043 raise err.__class__(
5045 klass=self.__class__,
5046 decode_path=decode_path,
5049 llen, vlen, v = 1, 0, lv[1:]
5050 sub_offset = offset + tlen + llen
5052 while v[:EOC_LEN].tobytes() != EOC:
5053 chunk, v = Any().decode(
5056 decode_path=decode_path + (str(chunk_i),),
5059 _ctx_immutable=False,
5061 vlen += chunk.tlvlen
5062 sub_offset += chunk.tlvlen
5064 tlvlen = tlen + llen + vlen + EOC_LEN
5065 obj = self.__class__(
5066 value=tlv[:tlvlen].tobytes(),
5068 optional=self.optional,
5069 _decoded=(offset, 0, tlvlen),
5072 obj.tag = t.tobytes()
5073 return obj, v[EOC_LEN:]
5074 except DecodeError as err:
5075 raise err.__class__(
5077 klass=self.__class__,
5078 decode_path=decode_path,
5082 raise NotEnoughData(
5083 "encoded length is longer than data",
5084 klass=self.__class__,
5085 decode_path=decode_path,
5088 tlvlen = tlen + llen + l
5089 v, tail = tlv[:tlvlen], v[l:]
5090 obj = self.__class__(
5093 optional=self.optional,
5094 _decoded=(offset, 0, tlvlen),
5096 obj.tag = t.tobytes()
5100 return pp_console_row(next(self.pps()))
5102 def pps(self, decode_path=()):
5105 asn1_type_name=self.asn1_type_name,
5106 obj_name=self.__class__.__name__,
5107 decode_path=decode_path,
5108 blob=self._value if self.ready else None,
5109 optional=self.optional,
5110 default=self == self.default,
5111 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5112 expl=None if self._expl is None else tag_decode(self._expl),
5117 expl_offset=self.expl_offset if self.expled else None,
5118 expl_tlen=self.expl_tlen if self.expled else None,
5119 expl_llen=self.expl_llen if self.expled else None,
5120 expl_vlen=self.expl_vlen if self.expled else None,
5121 expl_lenindef=self.expl_lenindef,
5122 lenindef=self.lenindef,
5125 defined_by, defined = self.defined or (None, None)
5126 if defined_by is not None:
5128 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5130 for pp in self.pps_lenindef(decode_path):
5134 ########################################################################
5135 # ASN.1 constructed types
5136 ########################################################################
5138 def get_def_by_path(defines_by_path, sub_decode_path):
5139 """Get define by decode path
5141 for path, define in defines_by_path:
5142 if len(path) != len(sub_decode_path):
5144 for p1, p2 in zip(path, sub_decode_path):
5145 if (not p1 is any) and (p1 != p2):
5151 def abs_decode_path(decode_path, rel_path):
5152 """Create an absolute decode path from current and relative ones
5154 :param decode_path: current decode path, starting point. Tuple of strings
5155 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5156 If first tuple's element is "/", then treat it as
5157 an absolute path, ignoring ``decode_path`` as
5158 starting point. Also this tuple can contain ".."
5159 elements, stripping the leading element from
5162 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5163 ("foo", "bar", "baz", "whatever")
5164 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5166 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5169 if rel_path[0] == "/":
5171 if rel_path[0] == "..":
5172 return abs_decode_path(decode_path[:-1], rel_path[1:])
5173 return decode_path + rel_path
5176 SequenceState = namedtuple("SequenceState", (
5190 ), **NAMEDTUPLE_KWARGS)
5193 class Sequence(Obj):
5194 """``SEQUENCE`` structure type
5196 You have to make specification of sequence::
5198 class Extension(Sequence):
5200 ("extnID", ObjectIdentifier()),
5201 ("critical", Boolean(default=False)),
5202 ("extnValue", OctetString()),
5205 Then, you can work with it as with dictionary.
5207 >>> ext = Extension()
5208 >>> Extension().specs
5210 ('extnID', OBJECT IDENTIFIER),
5211 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5212 ('extnValue', OCTET STRING),
5214 >>> ext["extnID"] = "1.2.3"
5215 Traceback (most recent call last):
5216 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5217 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5219 You can determine if sequence is ready to be encoded:
5224 Traceback (most recent call last):
5225 pyderasn.ObjNotReady: object is not ready: extnValue
5226 >>> ext["extnValue"] = OctetString(b"foobar")
5230 Value you want to assign, must have the same **type** as in
5231 corresponding specification, but it can have different tags,
5232 optional/default attributes -- they will be taken from specification
5235 class TBSCertificate(Sequence):
5237 ("version", Version(expl=tag_ctxc(0), default="v1")),
5240 >>> tbs = TBSCertificate()
5241 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5243 Assign ``None`` to remove value from sequence.
5245 You can set values in Sequence during its initialization:
5247 >>> AlgorithmIdentifier((
5248 ("algorithm", ObjectIdentifier("1.2.3")),
5249 ("parameters", Any(Null()))
5251 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5253 You can determine if value exists/set in the sequence and take its value:
5255 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5258 OBJECT IDENTIFIER 1.2.3
5260 But pay attention that if value has default, then it won't be (not
5261 in) in the sequence (because ``DEFAULT`` must not be encoded in
5262 DER), but you can read its value:
5264 >>> "critical" in ext, ext["critical"]
5265 (False, BOOLEAN False)
5266 >>> ext["critical"] = Boolean(True)
5267 >>> "critical" in ext, ext["critical"]
5268 (True, BOOLEAN True)
5270 All defaulted values are always optional.
5272 .. _allow_default_values_ctx:
5274 DER prohibits default value encoding and will raise an error if
5275 default value is unexpectedly met during decode.
5276 If :ref:`bered <bered_ctx>` context option is set, then no error
5277 will be raised, but ``bered`` attribute set. You can disable strict
5278 defaulted values existence validation by setting
5279 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5281 Two sequences are equal if they have equal specification (schema),
5282 implicit/explicit tagging and the same values.
5284 __slots__ = ("specs",)
5285 tag_default = tag_encode(form=TagFormConstructed, num=16)
5286 asn1_type_name = "SEQUENCE"
5298 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5300 schema = getattr(self, "schema", ())
5302 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
5305 if value is not None:
5306 if issubclass(value.__class__, Sequence):
5307 self._value = value._value
5308 elif hasattr(value, "__iter__"):
5309 for seq_key, seq_value in value:
5310 self[seq_key] = seq_value
5312 raise InvalidValueType((Sequence,))
5313 if default is not None:
5314 if not issubclass(default.__class__, Sequence):
5315 raise InvalidValueType((Sequence,))
5316 default_value = default._value
5317 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5318 default_obj.specs = self.specs
5319 default_obj._value = default_value
5320 self.default = default_obj
5322 self._value = copy(default_obj._value)
5326 for name, spec in iteritems(self.specs):
5327 value = self._value.get(name)
5338 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5340 return any(value.bered for value in itervalues(self._value))
5342 def __getstate__(self):
5343 return SequenceState(
5346 {k: copy(v) for k, v in iteritems(self._value)},
5359 def __setstate__(self, state):
5360 super(Sequence, self).__setstate__(state)
5361 self.specs = state.specs
5362 self._value = state.value
5363 self.tag = state.tag
5364 self._expl = state.expl
5365 self.default = state.default
5366 self.optional = state.optional
5367 self.offset = state.offset
5368 self.llen = state.llen
5369 self.vlen = state.vlen
5370 self.expl_lenindef = state.expl_lenindef
5371 self.lenindef = state.lenindef
5372 self.ber_encoded = state.ber_encoded
5374 def __eq__(self, their):
5375 if not isinstance(their, self.__class__):
5378 self.specs == their.specs and
5379 self.tag == their.tag and
5380 self._expl == their._expl and
5381 self._value == their._value
5392 return self.__class__(
5395 impl=self.tag if impl is None else impl,
5396 expl=self._expl if expl is None else expl,
5397 default=self.default if default is None else default,
5398 optional=self.optional if optional is None else optional,
5401 def __contains__(self, key):
5402 return key in self._value
5404 def __setitem__(self, key, value):
5405 spec = self.specs.get(key)
5407 raise ObjUnknown(key)
5409 self._value.pop(key, None)
5411 if not isinstance(value, spec.__class__):
5412 raise InvalidValueType((spec.__class__,))
5413 value = spec(value=value)
5414 if spec.default is not None and value == spec.default:
5415 self._value.pop(key, None)
5417 self._value[key] = value
5419 def __getitem__(self, key):
5420 value = self._value.get(key)
5421 if value is not None:
5423 spec = self.specs.get(key)
5425 raise ObjUnknown(key)
5426 if spec.default is not None:
5430 def _values_for_encoding(self):
5431 for name, spec in iteritems(self.specs):
5432 value = self._value.get(name)
5436 raise ObjNotReady(name)
5440 v = b"".join(v.encode() for v in self._values_for_encoding())
5441 return b"".join((self.tag, len_encode(len(v)), v))
5443 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5445 t, tlen, lv = tag_strip(tlv)
5446 except DecodeError as err:
5447 raise err.__class__(
5449 klass=self.__class__,
5450 decode_path=decode_path,
5455 klass=self.__class__,
5456 decode_path=decode_path,
5459 if tag_only: # pragma: no cover
5462 ctx_bered = ctx.get("bered", False)
5464 l, llen, v = len_decode(lv)
5465 except LenIndefForm as err:
5467 raise err.__class__(
5469 klass=self.__class__,
5470 decode_path=decode_path,
5473 l, llen, v = 0, 1, lv[1:]
5475 except DecodeError as err:
5476 raise err.__class__(
5478 klass=self.__class__,
5479 decode_path=decode_path,
5483 raise NotEnoughData(
5484 "encoded length is longer than data",
5485 klass=self.__class__,
5486 decode_path=decode_path,
5490 v, tail = v[:l], v[l:]
5492 sub_offset = offset + tlen + llen
5495 ctx_allow_default_values = ctx.get("allow_default_values", False)
5496 for name, spec in iteritems(self.specs):
5497 if spec.optional and (
5498 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5502 sub_decode_path = decode_path + (name,)
5504 value, v_tail = spec.decode(
5508 decode_path=sub_decode_path,
5510 _ctx_immutable=False,
5512 except TagMismatch as err:
5513 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5517 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5518 if defined is not None:
5519 defined_by, defined_spec = defined
5520 if issubclass(value.__class__, SequenceOf):
5521 for i, _value in enumerate(value):
5522 sub_sub_decode_path = sub_decode_path + (
5524 DecodePathDefBy(defined_by),
5526 defined_value, defined_tail = defined_spec.decode(
5527 memoryview(bytes(_value)),
5529 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5530 if value.expled else (value.tlen + value.llen)
5533 decode_path=sub_sub_decode_path,
5535 _ctx_immutable=False,
5537 if len(defined_tail) > 0:
5540 klass=self.__class__,
5541 decode_path=sub_sub_decode_path,
5544 _value.defined = (defined_by, defined_value)
5546 defined_value, defined_tail = defined_spec.decode(
5547 memoryview(bytes(value)),
5549 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5550 if value.expled else (value.tlen + value.llen)
5553 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5555 _ctx_immutable=False,
5557 if len(defined_tail) > 0:
5560 klass=self.__class__,
5561 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5564 value.defined = (defined_by, defined_value)
5566 value_len = value.fulllen
5568 sub_offset += value_len
5570 if spec.default is not None and value == spec.default:
5571 if ctx_bered or ctx_allow_default_values:
5575 "DEFAULT value met",
5576 klass=self.__class__,
5577 decode_path=sub_decode_path,
5580 values[name] = value
5582 spec_defines = getattr(spec, "defines", ())
5583 if len(spec_defines) == 0:
5584 defines_by_path = ctx.get("defines_by_path", ())
5585 if len(defines_by_path) > 0:
5586 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5587 if spec_defines is not None and len(spec_defines) > 0:
5588 for rel_path, schema in spec_defines:
5589 defined = schema.get(value, None)
5590 if defined is not None:
5591 ctx.setdefault("_defines", []).append((
5592 abs_decode_path(sub_decode_path[:-1], rel_path),
5596 if v[:EOC_LEN].tobytes() != EOC:
5599 klass=self.__class__,
5600 decode_path=decode_path,
5608 klass=self.__class__,
5609 decode_path=decode_path,
5612 obj = self.__class__(
5616 default=self.default,
5617 optional=self.optional,
5618 _decoded=(offset, llen, vlen),
5621 obj.lenindef = lenindef
5622 obj.ber_encoded = ber_encoded
5626 value = pp_console_row(next(self.pps()))
5628 for name in self.specs:
5629 _value = self._value.get(name)
5632 cols.append("%s: %s" % (name, repr(_value)))
5633 return "%s[%s]" % (value, "; ".join(cols))
5635 def pps(self, decode_path=()):
5638 asn1_type_name=self.asn1_type_name,
5639 obj_name=self.__class__.__name__,
5640 decode_path=decode_path,
5641 optional=self.optional,
5642 default=self == self.default,
5643 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5644 expl=None if self._expl is None else tag_decode(self._expl),
5649 expl_offset=self.expl_offset if self.expled else None,
5650 expl_tlen=self.expl_tlen if self.expled else None,
5651 expl_llen=self.expl_llen if self.expled else None,
5652 expl_vlen=self.expl_vlen if self.expled else None,
5653 expl_lenindef=self.expl_lenindef,
5654 lenindef=self.lenindef,
5655 ber_encoded=self.ber_encoded,
5658 for name in self.specs:
5659 value = self._value.get(name)
5662 yield value.pps(decode_path=decode_path + (name,))
5663 for pp in self.pps_lenindef(decode_path):
5667 class Set(Sequence):
5668 """``SET`` structure type
5670 Its usage is identical to :py:class:`pyderasn.Sequence`.
5672 .. _allow_unordered_set_ctx:
5674 DER prohibits unordered values encoding and will raise an error
5675 during decode. If :ref:`bered <bered_ctx>` context option is set,
5676 then no error will occur. Also you can disable strict values
5677 ordering check by setting ``"allow_unordered_set": True``
5678 :ref:`context <ctx>` option.
5681 tag_default = tag_encode(form=TagFormConstructed, num=17)
5682 asn1_type_name = "SET"
5685 raws = [v.encode() for v in self._values_for_encoding()]
5688 return b"".join((self.tag, len_encode(len(v)), v))
5690 def _specs_items(self):
5691 return iteritems(self.specs)
5693 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5695 t, tlen, lv = tag_strip(tlv)
5696 except DecodeError as err:
5697 raise err.__class__(
5699 klass=self.__class__,
5700 decode_path=decode_path,
5705 klass=self.__class__,
5706 decode_path=decode_path,
5712 ctx_bered = ctx.get("bered", False)
5714 l, llen, v = len_decode(lv)
5715 except LenIndefForm as err:
5717 raise err.__class__(
5719 klass=self.__class__,
5720 decode_path=decode_path,
5723 l, llen, v = 0, 1, lv[1:]
5725 except DecodeError as err:
5726 raise err.__class__(
5728 klass=self.__class__,
5729 decode_path=decode_path,
5733 raise NotEnoughData(
5734 "encoded length is longer than data",
5735 klass=self.__class__,
5739 v, tail = v[:l], v[l:]
5741 sub_offset = offset + tlen + llen
5744 ctx_allow_default_values = ctx.get("allow_default_values", False)
5745 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5746 value_prev = memoryview(v[:0])
5749 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5751 for name, spec in self._specs_items():
5752 sub_decode_path = decode_path + (name,)
5758 decode_path=sub_decode_path,
5761 _ctx_immutable=False,
5768 klass=self.__class__,
5769 decode_path=decode_path,
5772 value, v_tail = spec.decode(
5776 decode_path=sub_decode_path,
5778 _ctx_immutable=False,
5780 value_len = value.fulllen
5781 if value_prev.tobytes() > v[:value_len].tobytes():
5782 if ctx_bered or ctx_allow_unordered_set:
5786 "unordered " + self.asn1_type_name,
5787 klass=self.__class__,
5788 decode_path=sub_decode_path,
5791 if spec.default is None or value != spec.default:
5793 elif ctx_bered or ctx_allow_default_values:
5797 "DEFAULT value met",
5798 klass=self.__class__,
5799 decode_path=sub_decode_path,
5802 values[name] = value
5803 value_prev = v[:value_len]
5804 sub_offset += value_len
5807 obj = self.__class__(
5811 default=self.default,
5812 optional=self.optional,
5813 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5816 if v[:EOC_LEN].tobytes() != EOC:
5819 klass=self.__class__,
5820 decode_path=decode_path,
5826 for name, spec in iteritems(self.specs):
5827 if name not in values and not spec.optional:
5829 "%s value is not ready" % name,
5830 klass=self.__class__,
5831 decode_path=decode_path,
5834 obj.ber_encoded = ber_encoded
5838 SequenceOfState = namedtuple("SequenceOfState", (
5854 ), **NAMEDTUPLE_KWARGS)
5857 class SequenceOf(Obj):
5858 """``SEQUENCE OF`` sequence type
5860 For that kind of type you must specify the object it will carry on
5861 (bounds are for example here, not required)::
5863 class Ints(SequenceOf):
5868 >>> ints.append(Integer(123))
5869 >>> ints.append(Integer(234))
5871 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5872 >>> [int(i) for i in ints]
5874 >>> ints.append(Integer(345))
5875 Traceback (most recent call last):
5876 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5879 >>> ints[1] = Integer(345)
5881 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5883 Also you can initialize sequence with preinitialized values:
5885 >>> ints = Ints([Integer(123), Integer(234)])
5887 __slots__ = ("spec", "_bound_min", "_bound_max")
5888 tag_default = tag_encode(form=TagFormConstructed, num=16)
5889 asn1_type_name = "SEQUENCE OF"
5902 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5904 schema = getattr(self, "schema", None)
5906 raise ValueError("schema must be specified")
5908 self._bound_min, self._bound_max = getattr(
5912 ) if bounds is None else bounds
5914 if value is not None:
5915 self._value = self._value_sanitize(value)
5916 if default is not None:
5917 default_value = self._value_sanitize(default)
5918 default_obj = self.__class__(
5923 default_obj._value = default_value
5924 self.default = default_obj
5926 self._value = copy(default_obj._value)
5928 def _value_sanitize(self, value):
5929 if issubclass(value.__class__, SequenceOf):
5930 value = value._value
5931 elif hasattr(value, "__iter__"):
5934 raise InvalidValueType((self.__class__, iter))
5935 if not self._bound_min <= len(value) <= self._bound_max:
5936 raise BoundsError(self._bound_min, len(value), self._bound_max)
5938 if not isinstance(v, self.spec.__class__):
5939 raise InvalidValueType((self.spec.__class__,))
5944 return all(v.ready for v in self._value)
5948 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5950 return any(v.bered for v in self._value)
5952 def __getstate__(self):
5953 return SequenceOfState(
5956 [copy(v) for v in self._value],
5971 def __setstate__(self, state):
5972 super(SequenceOf, self).__setstate__(state)
5973 self.spec = state.spec
5974 self._value = state.value
5975 self._bound_min = state.bound_min
5976 self._bound_max = state.bound_max
5977 self.tag = state.tag
5978 self._expl = state.expl
5979 self.default = state.default
5980 self.optional = state.optional
5981 self.offset = state.offset
5982 self.llen = state.llen
5983 self.vlen = state.vlen
5984 self.expl_lenindef = state.expl_lenindef
5985 self.lenindef = state.lenindef
5986 self.ber_encoded = state.ber_encoded
5988 def __eq__(self, their):
5989 if isinstance(their, self.__class__):
5991 self.spec == their.spec and
5992 self.tag == their.tag and
5993 self._expl == their._expl and
5994 self._value == their._value
5996 if hasattr(their, "__iter__"):
5997 return self._value == list(their)
6009 return self.__class__(
6013 (self._bound_min, self._bound_max)
6014 if bounds is None else bounds
6016 impl=self.tag if impl is None else impl,
6017 expl=self._expl if expl is None else expl,
6018 default=self.default if default is None else default,
6019 optional=self.optional if optional is None else optional,
6022 def __contains__(self, key):
6023 return key in self._value
6025 def append(self, value):
6026 if not isinstance(value, self.spec.__class__):
6027 raise InvalidValueType((self.spec.__class__,))
6028 if len(self._value) + 1 > self._bound_max:
6031 len(self._value) + 1,
6034 self._value.append(value)
6037 self._assert_ready()
6038 return iter(self._value)
6041 self._assert_ready()
6042 return len(self._value)
6044 def __setitem__(self, key, value):
6045 if not isinstance(value, self.spec.__class__):
6046 raise InvalidValueType((self.spec.__class__,))
6047 self._value[key] = self.spec(value=value)
6049 def __getitem__(self, key):
6050 return self._value[key]
6052 def _values_for_encoding(self):
6053 return iter(self._value)
6056 v = b"".join(v.encode() for v in self._values_for_encoding())
6057 return b"".join((self.tag, len_encode(len(v)), v))
6059 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
6061 t, tlen, lv = tag_strip(tlv)
6062 except DecodeError as err:
6063 raise err.__class__(
6065 klass=self.__class__,
6066 decode_path=decode_path,
6071 klass=self.__class__,
6072 decode_path=decode_path,
6078 ctx_bered = ctx.get("bered", False)
6080 l, llen, v = len_decode(lv)
6081 except LenIndefForm as err:
6083 raise err.__class__(
6085 klass=self.__class__,
6086 decode_path=decode_path,
6089 l, llen, v = 0, 1, lv[1:]
6091 except DecodeError as err:
6092 raise err.__class__(
6094 klass=self.__class__,
6095 decode_path=decode_path,
6099 raise NotEnoughData(
6100 "encoded length is longer than data",
6101 klass=self.__class__,
6102 decode_path=decode_path,
6106 v, tail = v[:l], v[l:]
6108 sub_offset = offset + tlen + llen
6110 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6111 value_prev = memoryview(v[:0])
6115 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6117 sub_decode_path = decode_path + (str(len(_value)),)
6118 value, v_tail = spec.decode(
6122 decode_path=sub_decode_path,
6124 _ctx_immutable=False,
6126 value_len = value.fulllen
6128 if value_prev.tobytes() > v[:value_len].tobytes():
6129 if ctx_bered or ctx_allow_unordered_set:
6133 "unordered " + self.asn1_type_name,
6134 klass=self.__class__,
6135 decode_path=sub_decode_path,
6138 value_prev = v[:value_len]
6139 _value.append(value)
6140 sub_offset += value_len
6144 obj = self.__class__(
6147 bounds=(self._bound_min, self._bound_max),
6150 default=self.default,
6151 optional=self.optional,
6152 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6154 except BoundsError as err:
6157 klass=self.__class__,
6158 decode_path=decode_path,
6162 if v[:EOC_LEN].tobytes() != EOC:
6165 klass=self.__class__,
6166 decode_path=decode_path,
6171 obj.ber_encoded = ber_encoded
6176 pp_console_row(next(self.pps())),
6177 ", ".join(repr(v) for v in self._value),
6180 def pps(self, decode_path=()):
6183 asn1_type_name=self.asn1_type_name,
6184 obj_name=self.__class__.__name__,
6185 decode_path=decode_path,
6186 optional=self.optional,
6187 default=self == self.default,
6188 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6189 expl=None if self._expl is None else tag_decode(self._expl),
6194 expl_offset=self.expl_offset if self.expled else None,
6195 expl_tlen=self.expl_tlen if self.expled else None,
6196 expl_llen=self.expl_llen if self.expled else None,
6197 expl_vlen=self.expl_vlen if self.expled else None,
6198 expl_lenindef=self.expl_lenindef,
6199 lenindef=self.lenindef,
6200 ber_encoded=self.ber_encoded,
6203 for i, value in enumerate(self._value):
6204 yield value.pps(decode_path=decode_path + (str(i),))
6205 for pp in self.pps_lenindef(decode_path):
6209 class SetOf(SequenceOf):
6210 """``SET OF`` sequence type
6212 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6215 tag_default = tag_encode(form=TagFormConstructed, num=17)
6216 asn1_type_name = "SET OF"
6219 raws = [v.encode() for v in self._values_for_encoding()]
6222 return b"".join((self.tag, len_encode(len(v)), v))
6224 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6225 return super(SetOf, self)._decode(
6231 ordering_check=True,
6235 def obj_by_path(pypath): # pragma: no cover
6236 """Import object specified as string Python path
6238 Modules must be separated from classes/functions with ``:``.
6240 >>> obj_by_path("foo.bar:Baz")
6241 <class 'foo.bar.Baz'>
6242 >>> obj_by_path("foo.bar:Baz.boo")
6243 <classmethod 'foo.bar.Baz.boo'>
6245 mod, objs = pypath.rsplit(":", 1)
6246 from importlib import import_module
6247 obj = import_module(mod)
6248 for obj_name in objs.split("."):
6249 obj = getattr(obj, obj_name)
6253 def generic_decoder(): # pragma: no cover
6254 # All of this below is a big hack with self references
6255 choice = PrimitiveTypes()
6256 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6257 choice.specs["SetOf"] = SetOf(schema=choice)
6258 for i in six_xrange(31):
6259 choice.specs["SequenceOf%d" % i] = SequenceOf(
6263 choice.specs["Any"] = Any()
6265 # Class name equals to type name, to omit it from output
6266 class SEQUENCEOF(SequenceOf):
6274 with_decode_path=False,
6275 decode_path_only=(),
6277 def _pprint_pps(pps):
6279 if hasattr(pp, "_fields"):
6281 decode_path_only != () and
6282 pp.decode_path[:len(decode_path_only)] != decode_path_only
6285 if pp.asn1_type_name == Choice.asn1_type_name:
6287 pp_kwargs = pp._asdict()
6288 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6289 pp = _pp(**pp_kwargs)
6290 yield pp_console_row(
6295 with_colours=with_colours,
6296 with_decode_path=with_decode_path,
6297 decode_path_len_decrease=len(decode_path_only),
6299 for row in pp_console_blob(
6301 decode_path_len_decrease=len(decode_path_only),
6305 for row in _pprint_pps(pp):
6307 return "\n".join(_pprint_pps(obj.pps()))
6308 return SEQUENCEOF(), pprint_any
6311 def main(): # pragma: no cover
6313 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6314 parser.add_argument(
6318 help="Skip that number of bytes from the beginning",
6320 parser.add_argument(
6322 help="Python paths to dictionary with OIDs, comma separated",
6324 parser.add_argument(
6326 help="Python path to schema definition to use",
6328 parser.add_argument(
6329 "--defines-by-path",
6330 help="Python path to decoder's defines_by_path",
6332 parser.add_argument(
6334 action="store_true",
6335 help="Disallow BER encoding",
6337 parser.add_argument(
6338 "--print-decode-path",
6339 action="store_true",
6340 help="Print decode paths",
6342 parser.add_argument(
6343 "--decode-path-only",
6344 help="Print only specified decode path",
6346 parser.add_argument(
6348 action="store_true",
6349 help="Allow explicit tag out-of-bound",
6351 parser.add_argument(
6353 type=argparse.FileType("rb"),
6354 help="Path to DER file you want to decode",
6356 args = parser.parse_args()
6357 args.DERFile.seek(args.skip)
6358 der = memoryview(args.DERFile.read())
6359 args.DERFile.close()
6361 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6362 if args.oids else ()
6365 schema = obj_by_path(args.schema)
6366 from functools import partial
6367 pprinter = partial(pprint, big_blobs=True)
6369 schema, pprinter = generic_decoder()
6371 "bered": not args.nobered,
6372 "allow_expl_oob": args.allow_expl_oob,
6374 if args.defines_by_path is not None:
6375 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6376 obj, tail = schema().decode(der, ctx=ctx)
6380 with_colours=environ.get("NO_COLOR") is None,
6381 with_decode_path=args.print_decode_path,
6383 () if args.decode_path_only is None else
6384 tuple(args.decode_path_only.split(":"))
6388 print("\nTrailing data: %s" % hexenc(tail))
6391 if __name__ == "__main__":