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 schema. 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 string import ascii_letters
675 from string import digits
676 from sys import version_info
677 from unicodedata import category as unicat
679 from six import add_metaclass
680 from six import binary_type
681 from six import byte2int
682 from six import indexbytes
683 from six import int2byte
684 from six import integer_types
685 from six import iterbytes
686 from six import iteritems
687 from six import itervalues
689 from six import string_types
690 from six import text_type
691 from six import unichr as six_unichr
692 from six.moves import xrange as six_xrange
696 from termcolor import colored
697 except ImportError: # pragma: no cover
698 def colored(what, *args, **kwargs):
744 "TagClassApplication",
748 "TagFormConstructed",
759 TagClassUniversal = 0
760 TagClassApplication = 1 << 6
761 TagClassContext = 1 << 7
762 TagClassPrivate = 1 << 6 | 1 << 7
764 TagFormConstructed = 1 << 5
767 TagClassApplication: "APPLICATION ",
768 TagClassPrivate: "PRIVATE ",
769 TagClassUniversal: "UNIV ",
773 LENINDEF = b"\x80" # length indefinite mark
774 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
775 NAMEDTUPLE_KWARGS = {} if version_info < (3, 6) else {"module": __name__}
776 SET01 = frozenset("01")
777 DECIMALS = frozenset(digits)
782 if not set(value) <= DECIMALS:
783 raise ValueError("non-pure integer")
786 def fractions2float(fractions_raw):
787 pureint(fractions_raw)
788 return float("0." + fractions_raw)
791 ########################################################################
793 ########################################################################
795 class ASN1Error(ValueError):
799 class DecodeError(ASN1Error):
800 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
802 :param str msg: reason of decode failing
803 :param klass: optional exact DecodeError inherited class (like
804 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
805 :py:exc:`InvalidLength`)
806 :param decode_path: tuple of strings. It contains human
807 readable names of the fields through which
808 decoding process has passed
809 :param int offset: binary offset where failure happened
811 super(DecodeError, self).__init__()
814 self.decode_path = decode_path
820 "" if self.klass is None else self.klass.__name__,
822 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
823 if len(self.decode_path) > 0 else ""
825 ("(at %d)" % self.offset) if self.offset > 0 else "",
831 return "%s(%s)" % (self.__class__.__name__, self)
834 class NotEnoughData(DecodeError):
838 class ExceedingData(ASN1Error):
839 def __init__(self, nbytes):
840 super(ExceedingData, self).__init__()
844 return "%d trailing bytes" % self.nbytes
847 return "%s(%s)" % (self.__class__.__name__, self)
850 class LenIndefForm(DecodeError):
854 class TagMismatch(DecodeError):
858 class InvalidLength(DecodeError):
862 class InvalidOID(DecodeError):
866 class ObjUnknown(ASN1Error):
867 def __init__(self, name):
868 super(ObjUnknown, self).__init__()
872 return "object is unknown: %s" % self.name
875 return "%s(%s)" % (self.__class__.__name__, self)
878 class ObjNotReady(ASN1Error):
879 def __init__(self, name):
880 super(ObjNotReady, self).__init__()
884 return "object is not ready: %s" % self.name
887 return "%s(%s)" % (self.__class__.__name__, self)
890 class InvalidValueType(ASN1Error):
891 def __init__(self, expected_types):
892 super(InvalidValueType, self).__init__()
893 self.expected_types = expected_types
896 return "invalid value type, expected: %s" % ", ".join(
897 [repr(t) for t in self.expected_types]
901 return "%s(%s)" % (self.__class__.__name__, self)
904 class BoundsError(ASN1Error):
905 def __init__(self, bound_min, value, bound_max):
906 super(BoundsError, self).__init__()
907 self.bound_min = bound_min
909 self.bound_max = bound_max
912 return "unsatisfied bounds: %s <= %s <= %s" % (
919 return "%s(%s)" % (self.__class__.__name__, self)
922 ########################################################################
924 ########################################################################
926 _hexdecoder = getdecoder("hex")
927 _hexencoder = getencoder("hex")
931 """Binary data to hexadecimal string convert
933 return _hexdecoder(data)[0]
937 """Hexadecimal string to binary data convert
939 return _hexencoder(data)[0].decode("ascii")
942 def int_bytes_len(num, byte_len=8):
945 return int(ceil(float(num.bit_length()) / byte_len))
948 def zero_ended_encode(num):
949 octets = bytearray(int_bytes_len(num, 7))
951 octets[i] = num & 0x7F
955 octets[i] = 0x80 | (num & 0x7F)
961 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
962 """Encode tag to binary form
964 :param int num: tag's number
965 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
966 :py:data:`pyderasn.TagClassContext`,
967 :py:data:`pyderasn.TagClassApplication`,
968 :py:data:`pyderasn.TagClassPrivate`)
969 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
970 :py:data:`pyderasn.TagFormConstructed`)
974 return int2byte(klass | form | num)
975 # [XX|X|11111][1.......][1.......] ... [0.......]
976 return int2byte(klass | form | 31) + zero_ended_encode(num)
980 """Decode tag from binary form
984 No validation is performed, assuming that it has already passed.
986 It returns tuple with three integers, as
987 :py:func:`pyderasn.tag_encode` accepts.
989 first_octet = byte2int(tag)
990 klass = first_octet & 0xC0
991 form = first_octet & 0x20
992 if first_octet & 0x1F < 0x1F:
993 return (klass, form, first_octet & 0x1F)
995 for octet in iterbytes(tag[1:]):
998 return (klass, form, num)
1002 """Create CONTEXT PRIMITIVE tag
1004 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
1008 """Create CONTEXT CONSTRUCTED tag
1010 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
1013 def tag_strip(data):
1014 """Take off tag from the data
1016 :returns: (encoded tag, tag length, remaining data)
1019 raise NotEnoughData("no data at all")
1020 if byte2int(data) & 0x1F < 31:
1021 return data[:1], 1, data[1:]
1026 raise DecodeError("unfinished tag")
1027 if indexbytes(data, i) & 0x80 == 0:
1030 return data[:i], i, data[i:]
1036 octets = bytearray(int_bytes_len(l) + 1)
1037 octets[0] = 0x80 | (len(octets) - 1)
1038 for i in six_xrange(len(octets) - 1, 0, -1):
1039 octets[i] = l & 0xFF
1041 return bytes(octets)
1044 def len_decode(data):
1047 :returns: (decoded length, length's length, remaining data)
1048 :raises LenIndefForm: if indefinite form encoding is met
1051 raise NotEnoughData("no data at all")
1052 first_octet = byte2int(data)
1053 if first_octet & 0x80 == 0:
1054 return first_octet, 1, data[1:]
1055 octets_num = first_octet & 0x7F
1056 if octets_num + 1 > len(data):
1057 raise NotEnoughData("encoded length is longer than data")
1059 raise LenIndefForm()
1060 if byte2int(data[1:]) == 0:
1061 raise DecodeError("leading zeros")
1063 for v in iterbytes(data[1:1 + octets_num]):
1066 raise DecodeError("long form instead of short one")
1067 return l, 1 + octets_num, data[1 + octets_num:]
1070 ########################################################################
1072 ########################################################################
1074 class AutoAddSlots(type):
1075 def __new__(cls, name, bases, _dict):
1076 _dict["__slots__"] = _dict.get("__slots__", ())
1077 return type.__new__(cls, name, bases, _dict)
1080 BasicState = namedtuple("BasicState", (
1092 ), **NAMEDTUPLE_KWARGS)
1095 @add_metaclass(AutoAddSlots)
1097 """Common ASN.1 object class
1099 All ASN.1 types are inherited from it. It has metaclass that
1100 automatically adds ``__slots__`` to all inherited classes.
1124 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1125 self._expl = getattr(self, "expl", None) if expl is None else expl
1126 if self.tag != self.tag_default and self._expl is not None:
1127 raise ValueError("implicit and explicit tags can not be set simultaneously")
1128 if default is not None:
1130 self.optional = optional
1131 self.offset, self.llen, self.vlen = _decoded
1133 self.expl_lenindef = False
1134 self.lenindef = False
1135 self.ber_encoded = False
1138 def ready(self): # pragma: no cover
1139 """Is object ready to be encoded?
1141 raise NotImplementedError()
1143 def _assert_ready(self):
1145 raise ObjNotReady(self.__class__.__name__)
1149 """Is either object or any elements inside is BER encoded?
1151 return self.expl_lenindef or self.lenindef or self.ber_encoded
1155 """Is object decoded?
1157 return (self.llen + self.vlen) > 0
1159 def __getstate__(self): # pragma: no cover
1160 """Used for making safe to be mutable pickleable copies
1162 raise NotImplementedError()
1164 def __setstate__(self, state):
1165 if state.version != __version__:
1166 raise ValueError("data is pickled by different PyDERASN version")
1167 self.tag = state.tag
1168 self._expl = state.expl
1169 self.default = state.default
1170 self.optional = state.optional
1171 self.offset = state.offset
1172 self.llen = state.llen
1173 self.vlen = state.vlen
1174 self.expl_lenindef = state.expl_lenindef
1175 self.lenindef = state.lenindef
1176 self.ber_encoded = state.ber_encoded
1180 """See :ref:`decoding`
1182 return len(self.tag)
1186 """See :ref:`decoding`
1188 return self.tlen + self.llen + self.vlen
1190 def __str__(self): # pragma: no cover
1191 return self.__bytes__() if PY2 else self.__unicode__()
1193 def __ne__(self, their):
1194 return not(self == their)
1196 def __gt__(self, their): # pragma: no cover
1197 return not(self < their)
1199 def __le__(self, their): # pragma: no cover
1200 return (self == their) or (self < their)
1202 def __ge__(self, their): # pragma: no cover
1203 return (self == their) or (self > their)
1205 def _encode(self): # pragma: no cover
1206 raise NotImplementedError()
1208 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1209 raise NotImplementedError()
1212 """Encode the structure
1214 :returns: DER representation
1216 raw = self._encode()
1217 if self._expl is None:
1219 return b"".join((self._expl, len_encode(len(raw)), raw))
1221 def hexencode(self):
1222 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1224 return hexenc(self.encode())
1234 _ctx_immutable=True,
1238 :param data: either binary or memoryview
1239 :param int offset: initial data's offset
1240 :param bool leavemm: do we need to leave memoryview of remaining
1241 data as is, or convert it to bytes otherwise
1242 :param ctx: optional :ref:`context <ctx>` governing decoding process
1243 :param tag_only: decode only the tag, without length and contents
1244 (used only in Choice and Set structures, trying to
1245 determine if tag satisfies the schema)
1246 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1248 :returns: (Obj, remaining data)
1250 .. seealso:: :ref:`decoding`
1254 elif _ctx_immutable:
1256 tlv = memoryview(data)
1257 if self._expl is None:
1258 result = self._decode(
1261 decode_path=decode_path,
1270 t, tlen, lv = tag_strip(tlv)
1271 except DecodeError as err:
1272 raise err.__class__(
1274 klass=self.__class__,
1275 decode_path=decode_path,
1280 klass=self.__class__,
1281 decode_path=decode_path,
1285 l, llen, v = len_decode(lv)
1286 except LenIndefForm as err:
1287 if not ctx.get("bered", False):
1288 raise err.__class__(
1290 klass=self.__class__,
1291 decode_path=decode_path,
1295 offset += tlen + llen
1296 result = self._decode(
1299 decode_path=decode_path,
1303 if tag_only: # pragma: no cover
1306 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1307 if eoc_expected.tobytes() != EOC:
1310 klass=self.__class__,
1311 decode_path=decode_path,
1315 obj.expl_lenindef = True
1316 except DecodeError as err:
1317 raise err.__class__(
1319 klass=self.__class__,
1320 decode_path=decode_path,
1325 raise NotEnoughData(
1326 "encoded length is longer than data",
1327 klass=self.__class__,
1328 decode_path=decode_path,
1331 result = self._decode(
1333 offset=offset + tlen + llen,
1334 decode_path=decode_path,
1338 if tag_only: # pragma: no cover
1341 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1343 "explicit tag out-of-bound, longer than data",
1344 klass=self.__class__,
1345 decode_path=decode_path,
1348 return obj, (tail if leavemm else tail.tobytes())
1350 def decod(self, data, offset=0, decode_path=(), ctx=None):
1351 """Decode the data, check that tail is empty
1353 :raises ExceedingData: if tail is not empty
1355 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1356 (decode without tail) that also checks that there is no
1359 obj, tail = self.decode(
1362 decode_path=decode_path,
1367 raise ExceedingData(len(tail))
1370 def hexdecode(self, data, *args, **kwargs):
1371 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1373 return self.decode(hexdec(data), *args, **kwargs)
1375 def hexdecod(self, data, *args, **kwargs):
1376 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1378 return self.decod(hexdec(data), *args, **kwargs)
1382 """See :ref:`decoding`
1384 return self._expl is not None
1388 """See :ref:`decoding`
1393 def expl_tlen(self):
1394 """See :ref:`decoding`
1396 return len(self._expl)
1399 def expl_llen(self):
1400 """See :ref:`decoding`
1402 if self.expl_lenindef:
1404 return len(len_encode(self.tlvlen))
1407 def expl_offset(self):
1408 """See :ref:`decoding`
1410 return self.offset - self.expl_tlen - self.expl_llen
1413 def expl_vlen(self):
1414 """See :ref:`decoding`
1419 def expl_tlvlen(self):
1420 """See :ref:`decoding`
1422 return self.expl_tlen + self.expl_llen + self.expl_vlen
1425 def fulloffset(self):
1426 """See :ref:`decoding`
1428 return self.expl_offset if self.expled else self.offset
1432 """See :ref:`decoding`
1434 return self.expl_tlvlen if self.expled else self.tlvlen
1436 def pps_lenindef(self, decode_path):
1437 if self.lenindef and not (
1438 getattr(self, "defined", None) is not None and
1439 self.defined[1].lenindef
1442 asn1_type_name="EOC",
1444 decode_path=decode_path,
1446 self.offset + self.tlvlen -
1447 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1455 if self.expl_lenindef:
1457 asn1_type_name="EOC",
1458 obj_name="EXPLICIT",
1459 decode_path=decode_path,
1460 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1469 class DecodePathDefBy(object):
1470 """DEFINED BY representation inside decode path
1472 __slots__ = ("defined_by",)
1474 def __init__(self, defined_by):
1475 self.defined_by = defined_by
1477 def __ne__(self, their):
1478 return not(self == their)
1480 def __eq__(self, their):
1481 if not isinstance(their, self.__class__):
1483 return self.defined_by == their.defined_by
1486 return "DEFINED BY " + str(self.defined_by)
1489 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1492 ########################################################################
1494 ########################################################################
1496 PP = namedtuple("PP", (
1519 ), **NAMEDTUPLE_KWARGS)
1524 asn1_type_name="unknown",
1541 expl_lenindef=False,
1572 def _colourize(what, colour, with_colours, attrs=("bold",)):
1573 return colored(what, colour, attrs=attrs) if with_colours else what
1576 def colonize_hex(hexed):
1577 """Separate hexadecimal string with colons
1579 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1588 with_decode_path=False,
1589 decode_path_len_decrease=0,
1596 " " if pp.expl_offset is None else
1597 ("-%d" % (pp.offset - pp.expl_offset))
1599 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1601 col = _colourize(col, "red", with_colours, ())
1602 col += _colourize("B", "red", with_colours) if pp.bered else " "
1604 col = "[%d,%d,%4d]%s" % (
1608 LENINDEF_PP_CHAR if pp.lenindef else " "
1610 col = _colourize(col, "green", with_colours, ())
1612 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1613 if decode_path_len > 0:
1614 cols.append(" ." * decode_path_len)
1615 ent = pp.decode_path[-1]
1616 if isinstance(ent, DecodePathDefBy):
1617 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1618 value = str(ent.defined_by)
1621 len(oid_maps) > 0 and
1622 ent.defined_by.asn1_type_name ==
1623 ObjectIdentifier.asn1_type_name
1625 for oid_map in oid_maps:
1626 oid_name = oid_map.get(value)
1627 if oid_name is not None:
1628 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1630 if oid_name is None:
1631 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1633 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1634 if pp.expl is not None:
1635 klass, _, num = pp.expl
1636 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1637 cols.append(_colourize(col, "blue", with_colours))
1638 if pp.impl is not None:
1639 klass, _, num = pp.impl
1640 col = "[%s%d]" % (TagClassReprs[klass], num)
1641 cols.append(_colourize(col, "blue", with_colours))
1642 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1643 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1645 cols.append(_colourize("BER", "red", with_colours))
1646 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1647 if pp.value is not None:
1649 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1651 len(oid_maps) > 0 and
1652 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1654 for oid_map in oid_maps:
1655 oid_name = oid_map.get(value)
1656 if oid_name is not None:
1657 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1659 if pp.asn1_type_name == Integer.asn1_type_name:
1660 hex_repr = hex(int(pp.obj._value))[2:].upper()
1661 if len(hex_repr) % 2 != 0:
1662 hex_repr = "0" + hex_repr
1663 cols.append(_colourize(
1664 "(%s)" % colonize_hex(hex_repr),
1669 if pp.blob.__class__ == binary_type:
1670 cols.append(hexenc(pp.blob))
1671 elif pp.blob.__class__ == tuple:
1672 cols.append(", ".join(pp.blob))
1674 cols.append(_colourize("OPTIONAL", "red", with_colours))
1676 cols.append(_colourize("DEFAULT", "red", with_colours))
1677 if with_decode_path:
1678 cols.append(_colourize(
1679 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1683 return " ".join(cols)
1686 def pp_console_blob(pp, decode_path_len_decrease=0):
1687 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1688 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1689 if decode_path_len > 0:
1690 cols.append(" ." * (decode_path_len + 1))
1691 if pp.blob.__class__ == binary_type:
1692 blob = hexenc(pp.blob).upper()
1693 for i in six_xrange(0, len(blob), 32):
1694 chunk = blob[i:i + 32]
1695 yield " ".join(cols + [colonize_hex(chunk)])
1696 elif pp.blob.__class__ == tuple:
1697 yield " ".join(cols + [", ".join(pp.blob)])
1705 with_decode_path=False,
1706 decode_path_only=(),
1708 """Pretty print object
1710 :param Obj obj: object you want to pretty print
1711 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1712 Its human readable form is printed when OID is met
1713 :param big_blobs: if large binary objects are met (like OctetString
1714 values), do we need to print them too, on separate
1716 :param with_colours: colourize output, if ``termcolor`` library
1718 :param with_decode_path: print decode path
1719 :param decode_path_only: print only that specified decode path
1721 def _pprint_pps(pps):
1723 if hasattr(pp, "_fields"):
1725 decode_path_only != () and
1727 str(p) for p in pp.decode_path[:len(decode_path_only)]
1728 ) != decode_path_only
1732 yield pp_console_row(
1737 with_colours=with_colours,
1738 with_decode_path=with_decode_path,
1739 decode_path_len_decrease=len(decode_path_only),
1741 for row in pp_console_blob(
1743 decode_path_len_decrease=len(decode_path_only),
1747 yield pp_console_row(
1752 with_colours=with_colours,
1753 with_decode_path=with_decode_path,
1754 decode_path_len_decrease=len(decode_path_only),
1757 for row in _pprint_pps(pp):
1759 return "\n".join(_pprint_pps(obj.pps()))
1762 ########################################################################
1763 # ASN.1 primitive types
1764 ########################################################################
1766 BooleanState = namedtuple(
1768 BasicState._fields + ("value",),
1774 """``BOOLEAN`` boolean type
1776 >>> b = Boolean(True)
1778 >>> b == Boolean(True)
1784 tag_default = tag_encode(1)
1785 asn1_type_name = "BOOLEAN"
1797 :param value: set the value. Either boolean type, or
1798 :py:class:`pyderasn.Boolean` object
1799 :param bytes impl: override default tag with ``IMPLICIT`` one
1800 :param bytes expl: override default tag with ``EXPLICIT`` one
1801 :param default: set default value. Type same as in ``value``
1802 :param bool optional: is object ``OPTIONAL`` in sequence
1804 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1805 self._value = None if value is None else self._value_sanitize(value)
1806 if default is not None:
1807 default = self._value_sanitize(default)
1808 self.default = self.__class__(
1814 self._value = default
1816 def _value_sanitize(self, value):
1817 if value.__class__ == bool:
1819 if issubclass(value.__class__, Boolean):
1821 raise InvalidValueType((self.__class__, bool))
1825 return self._value is not None
1827 def __getstate__(self):
1828 return BooleanState(
1843 def __setstate__(self, state):
1844 super(Boolean, self).__setstate__(state)
1845 self._value = state.value
1847 def __nonzero__(self):
1848 self._assert_ready()
1852 self._assert_ready()
1855 def __eq__(self, their):
1856 if their.__class__ == bool:
1857 return self._value == their
1858 if not issubclass(their.__class__, Boolean):
1861 self._value == their._value and
1862 self.tag == their.tag and
1863 self._expl == their._expl
1874 return self.__class__(
1876 impl=self.tag if impl is None else impl,
1877 expl=self._expl if expl is None else expl,
1878 default=self.default if default is None else default,
1879 optional=self.optional if optional is None else optional,
1883 self._assert_ready()
1887 (b"\xFF" if self._value else b"\x00"),
1890 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1892 t, _, lv = tag_strip(tlv)
1893 except DecodeError as err:
1894 raise err.__class__(
1896 klass=self.__class__,
1897 decode_path=decode_path,
1902 klass=self.__class__,
1903 decode_path=decode_path,
1909 l, _, v = len_decode(lv)
1910 except DecodeError as err:
1911 raise err.__class__(
1913 klass=self.__class__,
1914 decode_path=decode_path,
1918 raise InvalidLength(
1919 "Boolean's length must be equal to 1",
1920 klass=self.__class__,
1921 decode_path=decode_path,
1925 raise NotEnoughData(
1926 "encoded length is longer than data",
1927 klass=self.__class__,
1928 decode_path=decode_path,
1931 first_octet = byte2int(v)
1933 if first_octet == 0:
1935 elif first_octet == 0xFF:
1937 elif ctx.get("bered", False):
1942 "unacceptable Boolean value",
1943 klass=self.__class__,
1944 decode_path=decode_path,
1947 obj = self.__class__(
1951 default=self.default,
1952 optional=self.optional,
1953 _decoded=(offset, 1, 1),
1955 obj.ber_encoded = ber_encoded
1959 return pp_console_row(next(self.pps()))
1961 def pps(self, decode_path=()):
1964 asn1_type_name=self.asn1_type_name,
1965 obj_name=self.__class__.__name__,
1966 decode_path=decode_path,
1967 value=str(self._value) if self.ready else None,
1968 optional=self.optional,
1969 default=self == self.default,
1970 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1971 expl=None if self._expl is None else tag_decode(self._expl),
1976 expl_offset=self.expl_offset if self.expled else None,
1977 expl_tlen=self.expl_tlen if self.expled else None,
1978 expl_llen=self.expl_llen if self.expled else None,
1979 expl_vlen=self.expl_vlen if self.expled else None,
1980 expl_lenindef=self.expl_lenindef,
1981 ber_encoded=self.ber_encoded,
1984 for pp in self.pps_lenindef(decode_path):
1988 IntegerState = namedtuple(
1990 BasicState._fields + ("specs", "value", "bound_min", "bound_max"),
1996 """``INTEGER`` integer type
1998 >>> b = Integer(-123)
2000 >>> b == Integer(-123)
2005 >>> Integer(2, bounds=(1, 3))
2007 >>> Integer(5, bounds=(1, 3))
2008 Traceback (most recent call last):
2009 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2013 class Version(Integer):
2020 >>> v = Version("v1")
2027 {'v3': 2, 'v1': 0, 'v2': 1}
2029 __slots__ = ("specs", "_bound_min", "_bound_max")
2030 tag_default = tag_encode(2)
2031 asn1_type_name = "INTEGER"
2045 :param value: set the value. Either integer type, named value
2046 (if ``schema`` is specified in the class), or
2047 :py:class:`pyderasn.Integer` object
2048 :param bounds: set ``(MIN, MAX)`` value constraint.
2049 (-inf, +inf) by default
2050 :param bytes impl: override default tag with ``IMPLICIT`` one
2051 :param bytes expl: override default tag with ``EXPLICIT`` one
2052 :param default: set default value. Type same as in ``value``
2053 :param bool optional: is object ``OPTIONAL`` in sequence
2055 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2057 specs = getattr(self, "schema", {}) if _specs is None else _specs
2058 self.specs = specs if specs.__class__ == dict else dict(specs)
2059 self._bound_min, self._bound_max = getattr(
2062 (float("-inf"), float("+inf")),
2063 ) if bounds is None else bounds
2064 if value is not None:
2065 self._value = self._value_sanitize(value)
2066 if default is not None:
2067 default = self._value_sanitize(default)
2068 self.default = self.__class__(
2074 if self._value is None:
2075 self._value = default
2077 def _value_sanitize(self, value):
2078 if isinstance(value, integer_types):
2080 elif issubclass(value.__class__, Integer):
2081 value = value._value
2082 elif value.__class__ == str:
2083 value = self.specs.get(value)
2085 raise ObjUnknown("integer value: %s" % value)
2087 raise InvalidValueType((self.__class__, int, str))
2088 if not self._bound_min <= value <= self._bound_max:
2089 raise BoundsError(self._bound_min, value, self._bound_max)
2094 return self._value is not None
2096 def __getstate__(self):
2097 return IntegerState(
2115 def __setstate__(self, state):
2116 super(Integer, self).__setstate__(state)
2117 self.specs = state.specs
2118 self._value = state.value
2119 self._bound_min = state.bound_min
2120 self._bound_max = state.bound_max
2123 self._assert_ready()
2124 return int(self._value)
2127 self._assert_ready()
2130 bytes(self._expl or b"") +
2131 str(self._value).encode("ascii"),
2134 def __eq__(self, their):
2135 if isinstance(their, integer_types):
2136 return self._value == their
2137 if not issubclass(their.__class__, Integer):
2140 self._value == their._value and
2141 self.tag == their.tag and
2142 self._expl == their._expl
2145 def __lt__(self, their):
2146 return self._value < their._value
2150 for name, value in iteritems(self.specs):
2151 if value == self._value:
2164 return self.__class__(
2167 (self._bound_min, self._bound_max)
2168 if bounds is None else bounds
2170 impl=self.tag if impl is None else impl,
2171 expl=self._expl if expl is None else expl,
2172 default=self.default if default is None else default,
2173 optional=self.optional if optional is None else optional,
2178 self._assert_ready()
2182 octets = bytearray([0])
2186 octets = bytearray()
2188 octets.append((value & 0xFF) ^ 0xFF)
2190 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2193 octets = bytearray()
2195 octets.append(value & 0xFF)
2197 if octets[-1] & 0x80 > 0:
2200 octets = bytes(octets)
2202 bytes_len = ceil(value.bit_length() / 8) or 1
2205 octets = value.to_bytes(
2210 except OverflowError:
2214 return b"".join((self.tag, len_encode(len(octets)), octets))
2216 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2218 t, _, lv = tag_strip(tlv)
2219 except DecodeError as err:
2220 raise err.__class__(
2222 klass=self.__class__,
2223 decode_path=decode_path,
2228 klass=self.__class__,
2229 decode_path=decode_path,
2235 l, llen, v = len_decode(lv)
2236 except DecodeError as err:
2237 raise err.__class__(
2239 klass=self.__class__,
2240 decode_path=decode_path,
2244 raise NotEnoughData(
2245 "encoded length is longer than data",
2246 klass=self.__class__,
2247 decode_path=decode_path,
2251 raise NotEnoughData(
2253 klass=self.__class__,
2254 decode_path=decode_path,
2257 v, tail = v[:l], v[l:]
2258 first_octet = byte2int(v)
2260 second_octet = byte2int(v[1:])
2262 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2263 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2266 "non normalized integer",
2267 klass=self.__class__,
2268 decode_path=decode_path,
2273 if first_octet & 0x80 > 0:
2274 octets = bytearray()
2275 for octet in bytearray(v):
2276 octets.append(octet ^ 0xFF)
2277 for octet in octets:
2278 value = (value << 8) | octet
2282 for octet in bytearray(v):
2283 value = (value << 8) | octet
2285 value = int.from_bytes(v, byteorder="big", signed=True)
2287 obj = self.__class__(
2289 bounds=(self._bound_min, self._bound_max),
2292 default=self.default,
2293 optional=self.optional,
2295 _decoded=(offset, llen, l),
2297 except BoundsError as err:
2300 klass=self.__class__,
2301 decode_path=decode_path,
2307 return pp_console_row(next(self.pps()))
2309 def pps(self, decode_path=()):
2312 asn1_type_name=self.asn1_type_name,
2313 obj_name=self.__class__.__name__,
2314 decode_path=decode_path,
2315 value=(self.named or str(self._value)) if self.ready else None,
2316 optional=self.optional,
2317 default=self == self.default,
2318 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2319 expl=None if self._expl is None else tag_decode(self._expl),
2324 expl_offset=self.expl_offset if self.expled else None,
2325 expl_tlen=self.expl_tlen if self.expled else None,
2326 expl_llen=self.expl_llen if self.expled else None,
2327 expl_vlen=self.expl_vlen if self.expled else None,
2328 expl_lenindef=self.expl_lenindef,
2331 for pp in self.pps_lenindef(decode_path):
2335 BitStringState = namedtuple(
2337 BasicState._fields + ("specs", "value", "tag_constructed", "defined"),
2342 class BitString(Obj):
2343 """``BIT STRING`` bit string type
2345 >>> BitString(b"hello world")
2346 BIT STRING 88 bits 68656c6c6f20776f726c64
2349 >>> b == b"hello world"
2354 >>> BitString("'0A3B5F291CD'H")
2355 BIT STRING 44 bits 0a3b5f291cd0
2356 >>> b = BitString("'010110000000'B")
2357 BIT STRING 12 bits 5800
2360 >>> b[0], b[1], b[2], b[3]
2361 (False, True, False, True)
2365 [False, True, False, True, True, False, False, False, False, False, False, False]
2369 class KeyUsage(BitString):
2371 ("digitalSignature", 0),
2372 ("nonRepudiation", 1),
2373 ("keyEncipherment", 2),
2376 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2377 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2379 ['nonRepudiation', 'keyEncipherment']
2381 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2385 Pay attention that BIT STRING can be encoded both in primitive
2386 and constructed forms. Decoder always checks constructed form tag
2387 additionally to specified primitive one. If BER decoding is
2388 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2389 of DER restrictions.
2391 __slots__ = ("tag_constructed", "specs", "defined")
2392 tag_default = tag_encode(3)
2393 asn1_type_name = "BIT STRING"
2406 :param value: set the value. Either binary type, tuple of named
2407 values (if ``schema`` is specified in the class),
2408 string in ``'XXX...'B`` form, or
2409 :py:class:`pyderasn.BitString` object
2410 :param bytes impl: override default tag with ``IMPLICIT`` one
2411 :param bytes expl: override default tag with ``EXPLICIT`` one
2412 :param default: set default value. Type same as in ``value``
2413 :param bool optional: is object ``OPTIONAL`` in sequence
2415 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2416 specs = getattr(self, "schema", {}) if _specs is None else _specs
2417 self.specs = specs if specs.__class__ == dict else dict(specs)
2418 self._value = None if value is None else self._value_sanitize(value)
2419 if default is not None:
2420 default = self._value_sanitize(default)
2421 self.default = self.__class__(
2427 self._value = default
2429 tag_klass, _, tag_num = tag_decode(self.tag)
2430 self.tag_constructed = tag_encode(
2432 form=TagFormConstructed,
2436 def _bits2octets(self, bits):
2437 if len(self.specs) > 0:
2438 bits = bits.rstrip("0")
2440 bits += "0" * ((8 - (bit_len % 8)) % 8)
2441 octets = bytearray(len(bits) // 8)
2442 for i in six_xrange(len(octets)):
2443 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2444 return bit_len, bytes(octets)
2446 def _value_sanitize(self, value):
2447 if isinstance(value, (string_types, binary_type)):
2449 isinstance(value, string_types) and
2450 value.startswith("'")
2452 if value.endswith("'B"):
2454 if not frozenset(value) <= SET01:
2455 raise ValueError("B's coding contains unacceptable chars")
2456 return self._bits2octets(value)
2457 if value.endswith("'H"):
2461 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2463 if value.__class__ == binary_type:
2464 return (len(value) * 8, value)
2465 raise InvalidValueType((self.__class__, string_types, binary_type))
2466 if value.__class__ == tuple:
2469 isinstance(value[0], integer_types) and
2470 value[1].__class__ == binary_type
2475 bit = self.specs.get(name)
2477 raise ObjUnknown("BitString value: %s" % name)
2480 return self._bits2octets("")
2481 bits = frozenset(bits)
2482 return self._bits2octets("".join(
2483 ("1" if bit in bits else "0")
2484 for bit in six_xrange(max(bits) + 1)
2486 if issubclass(value.__class__, BitString):
2488 raise InvalidValueType((self.__class__, binary_type, string_types))
2492 return self._value is not None
2494 def __getstate__(self):
2495 return BitStringState(
2509 self.tag_constructed,
2513 def __setstate__(self, state):
2514 super(BitString, self).__setstate__(state)
2515 self.specs = state.specs
2516 self._value = state.value
2517 self.tag_constructed = state.tag_constructed
2518 self.defined = state.defined
2521 self._assert_ready()
2522 for i in six_xrange(self._value[0]):
2527 self._assert_ready()
2528 return self._value[0]
2530 def __bytes__(self):
2531 self._assert_ready()
2532 return self._value[1]
2534 def __eq__(self, their):
2535 if their.__class__ == bytes:
2536 return self._value[1] == their
2537 if not issubclass(their.__class__, BitString):
2540 self._value == their._value and
2541 self.tag == their.tag and
2542 self._expl == their._expl
2547 return [name for name, bit in iteritems(self.specs) if self[bit]]
2557 return self.__class__(
2559 impl=self.tag if impl is None else impl,
2560 expl=self._expl if expl is None else expl,
2561 default=self.default if default is None else default,
2562 optional=self.optional if optional is None else optional,
2566 def __getitem__(self, key):
2567 if key.__class__ == int:
2568 bit_len, octets = self._value
2572 byte2int(memoryview(octets)[key // 8:]) >>
2575 if isinstance(key, string_types):
2576 value = self.specs.get(key)
2578 raise ObjUnknown("BitString value: %s" % key)
2580 raise InvalidValueType((int, str))
2583 self._assert_ready()
2584 bit_len, octets = self._value
2587 len_encode(len(octets) + 1),
2588 int2byte((8 - bit_len % 8) % 8),
2592 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2594 t, tlen, lv = tag_strip(tlv)
2595 except DecodeError as err:
2596 raise err.__class__(
2598 klass=self.__class__,
2599 decode_path=decode_path,
2603 if tag_only: # pragma: no cover
2606 l, llen, v = len_decode(lv)
2607 except DecodeError as err:
2608 raise err.__class__(
2610 klass=self.__class__,
2611 decode_path=decode_path,
2615 raise NotEnoughData(
2616 "encoded length is longer than data",
2617 klass=self.__class__,
2618 decode_path=decode_path,
2622 raise NotEnoughData(
2624 klass=self.__class__,
2625 decode_path=decode_path,
2628 pad_size = byte2int(v)
2629 if l == 1 and pad_size != 0:
2631 "invalid empty value",
2632 klass=self.__class__,
2633 decode_path=decode_path,
2639 klass=self.__class__,
2640 decode_path=decode_path,
2643 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2646 klass=self.__class__,
2647 decode_path=decode_path,
2650 v, tail = v[:l], v[l:]
2651 obj = self.__class__(
2652 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2655 default=self.default,
2656 optional=self.optional,
2658 _decoded=(offset, llen, l),
2661 if t != self.tag_constructed:
2663 klass=self.__class__,
2664 decode_path=decode_path,
2667 if not ctx.get("bered", False):
2669 "unallowed BER constructed encoding",
2670 klass=self.__class__,
2671 decode_path=decode_path,
2674 if tag_only: # pragma: no cover
2678 l, llen, v = len_decode(lv)
2679 except LenIndefForm:
2680 llen, l, v = 1, 0, lv[1:]
2682 except DecodeError as err:
2683 raise err.__class__(
2685 klass=self.__class__,
2686 decode_path=decode_path,
2690 raise NotEnoughData(
2691 "encoded length is longer than data",
2692 klass=self.__class__,
2693 decode_path=decode_path,
2696 if not lenindef and l == 0:
2697 raise NotEnoughData(
2699 klass=self.__class__,
2700 decode_path=decode_path,
2704 sub_offset = offset + tlen + llen
2708 if v[:EOC_LEN].tobytes() == EOC:
2715 "chunk out of bounds",
2716 klass=self.__class__,
2717 decode_path=decode_path + (str(len(chunks) - 1),),
2718 offset=chunks[-1].offset,
2720 sub_decode_path = decode_path + (str(len(chunks)),)
2722 chunk, v_tail = BitString().decode(
2725 decode_path=sub_decode_path,
2728 _ctx_immutable=False,
2732 "expected BitString encoded chunk",
2733 klass=self.__class__,
2734 decode_path=sub_decode_path,
2737 chunks.append(chunk)
2738 sub_offset += chunk.tlvlen
2739 vlen += chunk.tlvlen
2741 if len(chunks) == 0:
2744 klass=self.__class__,
2745 decode_path=decode_path,
2750 for chunk_i, chunk in enumerate(chunks[:-1]):
2751 if chunk.bit_len % 8 != 0:
2753 "BitString chunk is not multiple of 8 bits",
2754 klass=self.__class__,
2755 decode_path=decode_path + (str(chunk_i),),
2756 offset=chunk.offset,
2758 values.append(bytes(chunk))
2759 bit_len += chunk.bit_len
2760 chunk_last = chunks[-1]
2761 values.append(bytes(chunk_last))
2762 bit_len += chunk_last.bit_len
2763 obj = self.__class__(
2764 value=(bit_len, b"".join(values)),
2767 default=self.default,
2768 optional=self.optional,
2770 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2772 obj.lenindef = lenindef
2773 obj.ber_encoded = True
2774 return obj, (v[EOC_LEN:] if lenindef else v)
2777 return pp_console_row(next(self.pps()))
2779 def pps(self, decode_path=()):
2783 bit_len, blob = self._value
2784 value = "%d bits" % bit_len
2785 if len(self.specs) > 0:
2786 blob = tuple(self.named)
2789 asn1_type_name=self.asn1_type_name,
2790 obj_name=self.__class__.__name__,
2791 decode_path=decode_path,
2794 optional=self.optional,
2795 default=self == self.default,
2796 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2797 expl=None if self._expl is None else tag_decode(self._expl),
2802 expl_offset=self.expl_offset if self.expled else None,
2803 expl_tlen=self.expl_tlen if self.expled else None,
2804 expl_llen=self.expl_llen if self.expled else None,
2805 expl_vlen=self.expl_vlen if self.expled else None,
2806 expl_lenindef=self.expl_lenindef,
2807 lenindef=self.lenindef,
2808 ber_encoded=self.ber_encoded,
2811 defined_by, defined = self.defined or (None, None)
2812 if defined_by is not None:
2814 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2816 for pp in self.pps_lenindef(decode_path):
2820 OctetStringState = namedtuple(
2822 BasicState._fields + (
2833 class OctetString(Obj):
2834 """``OCTET STRING`` binary string type
2836 >>> s = OctetString(b"hello world")
2837 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2838 >>> s == OctetString(b"hello world")
2843 >>> OctetString(b"hello", bounds=(4, 4))
2844 Traceback (most recent call last):
2845 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2846 >>> OctetString(b"hell", bounds=(4, 4))
2847 OCTET STRING 4 bytes 68656c6c
2851 Pay attention that OCTET STRING can be encoded both in primitive
2852 and constructed forms. Decoder always checks constructed form tag
2853 additionally to specified primitive one. If BER decoding is
2854 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2855 of DER restrictions.
2857 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2858 tag_default = tag_encode(4)
2859 asn1_type_name = "OCTET STRING"
2873 :param value: set the value. Either binary type, or
2874 :py:class:`pyderasn.OctetString` object
2875 :param bounds: set ``(MIN, MAX)`` value size constraint.
2876 (-inf, +inf) by default
2877 :param bytes impl: override default tag with ``IMPLICIT`` one
2878 :param bytes expl: override default tag with ``EXPLICIT`` one
2879 :param default: set default value. Type same as in ``value``
2880 :param bool optional: is object ``OPTIONAL`` in sequence
2882 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2884 self._bound_min, self._bound_max = getattr(
2888 ) if bounds is None else bounds
2889 if value is not None:
2890 self._value = self._value_sanitize(value)
2891 if default is not None:
2892 default = self._value_sanitize(default)
2893 self.default = self.__class__(
2898 if self._value is None:
2899 self._value = default
2901 tag_klass, _, tag_num = tag_decode(self.tag)
2902 self.tag_constructed = tag_encode(
2904 form=TagFormConstructed,
2908 def _value_sanitize(self, value):
2909 if value.__class__ == binary_type:
2911 elif issubclass(value.__class__, OctetString):
2912 value = value._value
2914 raise InvalidValueType((self.__class__, bytes))
2915 if not self._bound_min <= len(value) <= self._bound_max:
2916 raise BoundsError(self._bound_min, len(value), self._bound_max)
2921 return self._value is not None
2923 def __getstate__(self):
2924 return OctetStringState(
2939 self.tag_constructed,
2943 def __setstate__(self, state):
2944 super(OctetString, self).__setstate__(state)
2945 self._value = state.value
2946 self._bound_min = state.bound_min
2947 self._bound_max = state.bound_max
2948 self.tag_constructed = state.tag_constructed
2949 self.defined = state.defined
2951 def __bytes__(self):
2952 self._assert_ready()
2955 def __eq__(self, their):
2956 if their.__class__ == binary_type:
2957 return self._value == their
2958 if not issubclass(their.__class__, OctetString):
2961 self._value == their._value and
2962 self.tag == their.tag and
2963 self._expl == their._expl
2966 def __lt__(self, their):
2967 return self._value < their._value
2978 return self.__class__(
2981 (self._bound_min, self._bound_max)
2982 if bounds is None else bounds
2984 impl=self.tag if impl is None else impl,
2985 expl=self._expl if expl is None else expl,
2986 default=self.default if default is None else default,
2987 optional=self.optional if optional is None else optional,
2991 self._assert_ready()
2994 len_encode(len(self._value)),
2998 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3000 t, tlen, lv = tag_strip(tlv)
3001 except DecodeError as err:
3002 raise err.__class__(
3004 klass=self.__class__,
3005 decode_path=decode_path,
3012 l, llen, v = len_decode(lv)
3013 except DecodeError as err:
3014 raise err.__class__(
3016 klass=self.__class__,
3017 decode_path=decode_path,
3021 raise NotEnoughData(
3022 "encoded length is longer than data",
3023 klass=self.__class__,
3024 decode_path=decode_path,
3027 v, tail = v[:l], v[l:]
3029 obj = self.__class__(
3031 bounds=(self._bound_min, self._bound_max),
3034 default=self.default,
3035 optional=self.optional,
3036 _decoded=(offset, llen, l),
3039 except DecodeError as err:
3042 klass=self.__class__,
3043 decode_path=decode_path,
3046 except BoundsError as err:
3049 klass=self.__class__,
3050 decode_path=decode_path,
3054 if t != self.tag_constructed:
3056 klass=self.__class__,
3057 decode_path=decode_path,
3060 if not ctx.get("bered", False):
3062 "unallowed BER constructed encoding",
3063 klass=self.__class__,
3064 decode_path=decode_path,
3071 l, llen, v = len_decode(lv)
3072 except LenIndefForm:
3073 llen, l, v = 1, 0, lv[1:]
3075 except DecodeError as err:
3076 raise err.__class__(
3078 klass=self.__class__,
3079 decode_path=decode_path,
3083 raise NotEnoughData(
3084 "encoded length is longer than data",
3085 klass=self.__class__,
3086 decode_path=decode_path,
3090 sub_offset = offset + tlen + llen
3094 if v[:EOC_LEN].tobytes() == EOC:
3101 "chunk out of bounds",
3102 klass=self.__class__,
3103 decode_path=decode_path + (str(len(chunks) - 1),),
3104 offset=chunks[-1].offset,
3106 sub_decode_path = decode_path + (str(len(chunks)),)
3108 chunk, v_tail = OctetString().decode(
3111 decode_path=sub_decode_path,
3114 _ctx_immutable=False,
3118 "expected OctetString encoded chunk",
3119 klass=self.__class__,
3120 decode_path=sub_decode_path,
3123 chunks.append(chunk)
3124 sub_offset += chunk.tlvlen
3125 vlen += chunk.tlvlen
3128 obj = self.__class__(
3129 value=b"".join(bytes(chunk) for chunk in chunks),
3130 bounds=(self._bound_min, self._bound_max),
3133 default=self.default,
3134 optional=self.optional,
3135 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3138 except DecodeError as err:
3141 klass=self.__class__,
3142 decode_path=decode_path,
3145 except BoundsError as err:
3148 klass=self.__class__,
3149 decode_path=decode_path,
3152 obj.lenindef = lenindef
3153 obj.ber_encoded = True
3154 return obj, (v[EOC_LEN:] if lenindef else v)
3157 return pp_console_row(next(self.pps()))
3159 def pps(self, decode_path=()):
3162 asn1_type_name=self.asn1_type_name,
3163 obj_name=self.__class__.__name__,
3164 decode_path=decode_path,
3165 value=("%d bytes" % len(self._value)) if self.ready else None,
3166 blob=self._value if self.ready else None,
3167 optional=self.optional,
3168 default=self == self.default,
3169 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3170 expl=None if self._expl is None else tag_decode(self._expl),
3175 expl_offset=self.expl_offset if self.expled else None,
3176 expl_tlen=self.expl_tlen if self.expled else None,
3177 expl_llen=self.expl_llen if self.expled else None,
3178 expl_vlen=self.expl_vlen if self.expled else None,
3179 expl_lenindef=self.expl_lenindef,
3180 lenindef=self.lenindef,
3181 ber_encoded=self.ber_encoded,
3184 defined_by, defined = self.defined or (None, None)
3185 if defined_by is not None:
3187 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3189 for pp in self.pps_lenindef(decode_path):
3193 NullState = namedtuple("NullState", BasicState._fields, **NAMEDTUPLE_KWARGS)
3197 """``NULL`` null object
3205 tag_default = tag_encode(5)
3206 asn1_type_name = "NULL"
3210 value=None, # unused, but Sequence passes it
3217 :param bytes impl: override default tag with ``IMPLICIT`` one
3218 :param bytes expl: override default tag with ``EXPLICIT`` one
3219 :param bool optional: is object ``OPTIONAL`` in sequence
3221 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3228 def __getstate__(self):
3243 def __eq__(self, their):
3244 if not issubclass(their.__class__, Null):
3247 self.tag == their.tag and
3248 self._expl == their._expl
3258 return self.__class__(
3259 impl=self.tag if impl is None else impl,
3260 expl=self._expl if expl is None else expl,
3261 optional=self.optional if optional is None else optional,
3265 return self.tag + len_encode(0)
3267 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3269 t, _, lv = tag_strip(tlv)
3270 except DecodeError as err:
3271 raise err.__class__(
3273 klass=self.__class__,
3274 decode_path=decode_path,
3279 klass=self.__class__,
3280 decode_path=decode_path,
3283 if tag_only: # pragma: no cover
3286 l, _, v = len_decode(lv)
3287 except DecodeError as err:
3288 raise err.__class__(
3290 klass=self.__class__,
3291 decode_path=decode_path,
3295 raise InvalidLength(
3296 "Null must have zero length",
3297 klass=self.__class__,
3298 decode_path=decode_path,
3301 obj = self.__class__(
3304 optional=self.optional,
3305 _decoded=(offset, 1, 0),
3310 return pp_console_row(next(self.pps()))
3312 def pps(self, decode_path=()):
3315 asn1_type_name=self.asn1_type_name,
3316 obj_name=self.__class__.__name__,
3317 decode_path=decode_path,
3318 optional=self.optional,
3319 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3320 expl=None if self._expl is None else tag_decode(self._expl),
3325 expl_offset=self.expl_offset if self.expled else None,
3326 expl_tlen=self.expl_tlen if self.expled else None,
3327 expl_llen=self.expl_llen if self.expled else None,
3328 expl_vlen=self.expl_vlen if self.expled else None,
3329 expl_lenindef=self.expl_lenindef,
3332 for pp in self.pps_lenindef(decode_path):
3336 ObjectIdentifierState = namedtuple(
3337 "ObjectIdentifierState",
3338 BasicState._fields + ("value", "defines"),
3343 class ObjectIdentifier(Obj):
3344 """``OBJECT IDENTIFIER`` OID type
3346 >>> oid = ObjectIdentifier((1, 2, 3))
3347 OBJECT IDENTIFIER 1.2.3
3348 >>> oid == ObjectIdentifier("1.2.3")
3354 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3355 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3357 >>> str(ObjectIdentifier((3, 1)))
3358 Traceback (most recent call last):
3359 pyderasn.InvalidOID: unacceptable first arc value
3361 __slots__ = ("defines",)
3362 tag_default = tag_encode(6)
3363 asn1_type_name = "OBJECT IDENTIFIER"
3376 :param value: set the value. Either tuples of integers,
3377 string of "."-concatenated integers, or
3378 :py:class:`pyderasn.ObjectIdentifier` object
3379 :param defines: sequence of tuples. Each tuple has two elements.
3380 First one is relative to current one decode
3381 path, aiming to the field defined by that OID.
3382 Read about relative path in
3383 :py:func:`pyderasn.abs_decode_path`. Second
3384 tuple element is ``{OID: pyderasn.Obj()}``
3385 dictionary, mapping between current OID value
3386 and structure applied to defined field.
3387 :ref:`Read about DEFINED BY <definedby>`
3388 :param bytes impl: override default tag with ``IMPLICIT`` one
3389 :param bytes expl: override default tag with ``EXPLICIT`` one
3390 :param default: set default value. Type same as in ``value``
3391 :param bool optional: is object ``OPTIONAL`` in sequence
3393 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3395 if value is not None:
3396 self._value = self._value_sanitize(value)
3397 if default is not None:
3398 default = self._value_sanitize(default)
3399 self.default = self.__class__(
3404 if self._value is None:
3405 self._value = default
3406 self.defines = defines
3408 def __add__(self, their):
3409 if their.__class__ == tuple:
3410 return self.__class__(self._value + their)
3411 if isinstance(their, self.__class__):
3412 return self.__class__(self._value + their._value)
3413 raise InvalidValueType((self.__class__, tuple))
3415 def _value_sanitize(self, value):
3416 if issubclass(value.__class__, ObjectIdentifier):
3418 if isinstance(value, string_types):
3420 value = tuple(pureint(arc) for arc in value.split("."))
3422 raise InvalidOID("unacceptable arcs values")
3423 if value.__class__ == tuple:
3425 raise InvalidOID("less than 2 arcs")
3426 first_arc = value[0]
3427 if first_arc in (0, 1):
3428 if not (0 <= value[1] <= 39):
3429 raise InvalidOID("second arc is too wide")
3430 elif first_arc == 2:
3433 raise InvalidOID("unacceptable first arc value")
3434 if not all(arc >= 0 for arc in value):
3435 raise InvalidOID("negative arc value")
3437 raise InvalidValueType((self.__class__, str, tuple))
3441 return self._value is not None
3443 def __getstate__(self):
3444 return ObjectIdentifierState(
3460 def __setstate__(self, state):
3461 super(ObjectIdentifier, self).__setstate__(state)
3462 self._value = state.value
3463 self.defines = state.defines
3466 self._assert_ready()
3467 return iter(self._value)
3470 return ".".join(str(arc) for arc in self._value or ())
3473 self._assert_ready()
3476 bytes(self._expl or b"") +
3477 str(self._value).encode("ascii"),
3480 def __eq__(self, their):
3481 if their.__class__ == tuple:
3482 return self._value == their
3483 if not issubclass(their.__class__, ObjectIdentifier):
3486 self.tag == their.tag and
3487 self._expl == their._expl and
3488 self._value == their._value
3491 def __lt__(self, their):
3492 return self._value < their._value
3503 return self.__class__(
3505 defines=self.defines if defines is None else defines,
3506 impl=self.tag if impl is None else impl,
3507 expl=self._expl if expl is None else expl,
3508 default=self.default if default is None else default,
3509 optional=self.optional if optional is None else optional,
3513 self._assert_ready()
3515 first_value = value[1]
3516 first_arc = value[0]
3519 elif first_arc == 1:
3521 elif first_arc == 2:
3523 else: # pragma: no cover
3524 raise RuntimeError("invalid arc is stored")
3525 octets = [zero_ended_encode(first_value)]
3526 for arc in value[2:]:
3527 octets.append(zero_ended_encode(arc))
3528 v = b"".join(octets)
3529 return b"".join((self.tag, len_encode(len(v)), v))
3531 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3533 t, _, lv = tag_strip(tlv)
3534 except DecodeError as err:
3535 raise err.__class__(
3537 klass=self.__class__,
3538 decode_path=decode_path,
3543 klass=self.__class__,
3544 decode_path=decode_path,
3547 if tag_only: # pragma: no cover
3550 l, llen, v = len_decode(lv)
3551 except DecodeError as err:
3552 raise err.__class__(
3554 klass=self.__class__,
3555 decode_path=decode_path,
3559 raise NotEnoughData(
3560 "encoded length is longer than data",
3561 klass=self.__class__,
3562 decode_path=decode_path,
3566 raise NotEnoughData(
3568 klass=self.__class__,
3569 decode_path=decode_path,
3572 v, tail = v[:l], v[l:]
3579 octet = indexbytes(v, i)
3580 if i == 0 and octet == 0x80:
3581 if ctx.get("bered", False):
3584 raise DecodeError("non normalized arc encoding")
3585 arc = (arc << 7) | (octet & 0x7F)
3586 if octet & 0x80 == 0:
3594 klass=self.__class__,
3595 decode_path=decode_path,
3599 second_arc = arcs[0]
3600 if 0 <= second_arc <= 39:
3602 elif 40 <= second_arc <= 79:
3608 obj = self.__class__(
3609 value=tuple([first_arc, second_arc] + arcs[1:]),
3612 default=self.default,
3613 optional=self.optional,
3614 _decoded=(offset, llen, l),
3617 obj.ber_encoded = True
3621 return pp_console_row(next(self.pps()))
3623 def pps(self, decode_path=()):
3626 asn1_type_name=self.asn1_type_name,
3627 obj_name=self.__class__.__name__,
3628 decode_path=decode_path,
3629 value=str(self) if self.ready else None,
3630 optional=self.optional,
3631 default=self == self.default,
3632 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3633 expl=None if self._expl is None else tag_decode(self._expl),
3638 expl_offset=self.expl_offset if self.expled else None,
3639 expl_tlen=self.expl_tlen if self.expled else None,
3640 expl_llen=self.expl_llen if self.expled else None,
3641 expl_vlen=self.expl_vlen if self.expled else None,
3642 expl_lenindef=self.expl_lenindef,
3643 ber_encoded=self.ber_encoded,
3646 for pp in self.pps_lenindef(decode_path):
3650 class Enumerated(Integer):
3651 """``ENUMERATED`` integer type
3653 This type is identical to :py:class:`pyderasn.Integer`, but requires
3654 schema to be specified and does not accept values missing from it.
3657 tag_default = tag_encode(10)
3658 asn1_type_name = "ENUMERATED"
3669 bounds=None, # dummy argument, workability for Integer.decode
3671 super(Enumerated, self).__init__(
3672 value, bounds, impl, expl, default, optional, _specs, _decoded,
3674 if len(self.specs) == 0:
3675 raise ValueError("schema must be specified")
3677 def _value_sanitize(self, value):
3678 if isinstance(value, self.__class__):
3679 value = value._value
3680 elif isinstance(value, integer_types):
3681 for _value in itervalues(self.specs):
3686 "unknown integer value: %s" % value,
3687 klass=self.__class__,
3689 elif isinstance(value, string_types):
3690 value = self.specs.get(value)
3692 raise ObjUnknown("integer value: %s" % value)
3694 raise InvalidValueType((self.__class__, int, str))
3706 return self.__class__(
3708 impl=self.tag if impl is None else impl,
3709 expl=self._expl if expl is None else expl,
3710 default=self.default if default is None else default,
3711 optional=self.optional if optional is None else optional,
3716 def escape_control_unicode(c):
3717 if unicat(c)[0] == "C":
3718 c = repr(c).lstrip("u").strip("'")
3722 class CommonString(OctetString):
3723 """Common class for all strings
3725 Everything resembles :py:class:`pyderasn.OctetString`, except
3726 ability to deal with unicode text strings.
3728 >>> hexenc("привет мир".encode("utf-8"))
3729 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3730 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3732 >>> s = UTF8String("привет мир")
3733 UTF8String UTF8String привет мир
3735 'привет мир'
3736 >>> hexenc(bytes(s))
3737 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3739 >>> PrintableString("привет мир")
3740 Traceback (most recent call last):
3741 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3743 >>> BMPString("ада", bounds=(2, 2))
3744 Traceback (most recent call last):
3745 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3746 >>> s = BMPString("ад", bounds=(2, 2))
3749 >>> hexenc(bytes(s))
3757 * - :py:class:`pyderasn.UTF8String`
3759 * - :py:class:`pyderasn.NumericString`
3761 * - :py:class:`pyderasn.PrintableString`
3763 * - :py:class:`pyderasn.TeletexString`
3765 * - :py:class:`pyderasn.T61String`
3767 * - :py:class:`pyderasn.VideotexString`
3769 * - :py:class:`pyderasn.IA5String`
3771 * - :py:class:`pyderasn.GraphicString`
3773 * - :py:class:`pyderasn.VisibleString`
3775 * - :py:class:`pyderasn.ISO646String`
3777 * - :py:class:`pyderasn.GeneralString`
3779 * - :py:class:`pyderasn.UniversalString`
3781 * - :py:class:`pyderasn.BMPString`
3786 def _value_sanitize(self, value):
3788 value_decoded = None
3789 if isinstance(value, self.__class__):
3790 value_raw = value._value
3791 elif value.__class__ == text_type:
3792 value_decoded = value
3793 elif value.__class__ == binary_type:
3796 raise InvalidValueType((self.__class__, text_type, binary_type))
3799 value_decoded.encode(self.encoding)
3800 if value_raw is None else value_raw
3803 value_raw.decode(self.encoding)
3804 if value_decoded is None else value_decoded
3806 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3807 raise DecodeError(str(err))
3808 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3816 def __eq__(self, their):
3817 if their.__class__ == binary_type:
3818 return self._value == their
3819 if their.__class__ == text_type:
3820 return self._value == their.encode(self.encoding)
3821 if not isinstance(their, self.__class__):
3824 self._value == their._value and
3825 self.tag == their.tag and
3826 self._expl == their._expl
3829 def __unicode__(self):
3831 return self._value.decode(self.encoding)
3832 return text_type(self._value)
3835 return pp_console_row(next(self.pps(no_unicode=PY2)))
3837 def pps(self, decode_path=(), no_unicode=False):
3841 hexenc(bytes(self)) if no_unicode else
3842 "".join(escape_control_unicode(c) for c in self.__unicode__())
3846 asn1_type_name=self.asn1_type_name,
3847 obj_name=self.__class__.__name__,
3848 decode_path=decode_path,
3850 optional=self.optional,
3851 default=self == self.default,
3852 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3853 expl=None if self._expl is None else tag_decode(self._expl),
3858 expl_offset=self.expl_offset if self.expled else None,
3859 expl_tlen=self.expl_tlen if self.expled else None,
3860 expl_llen=self.expl_llen if self.expled else None,
3861 expl_vlen=self.expl_vlen if self.expled else None,
3862 expl_lenindef=self.expl_lenindef,
3863 ber_encoded=self.ber_encoded,
3866 for pp in self.pps_lenindef(decode_path):
3870 class UTF8String(CommonString):
3872 tag_default = tag_encode(12)
3874 asn1_type_name = "UTF8String"
3877 class AllowableCharsMixin(object):
3879 def allowable_chars(self):
3881 return self._allowable_chars
3882 return frozenset(six_unichr(c) for c in self._allowable_chars)
3885 class NumericString(AllowableCharsMixin, CommonString):
3888 Its value is properly sanitized: only ASCII digits with spaces can
3891 >>> NumericString().allowable_chars
3892 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3895 tag_default = tag_encode(18)
3897 asn1_type_name = "NumericString"
3898 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3900 def _value_sanitize(self, value):
3901 value = super(NumericString, self)._value_sanitize(value)
3902 if not frozenset(value) <= self._allowable_chars:
3903 raise DecodeError("non-numeric value")
3907 PrintableStringState = namedtuple(
3908 "PrintableStringState",
3909 OctetStringState._fields + ("allowable_chars",),
3914 class PrintableString(AllowableCharsMixin, CommonString):
3917 Its value is properly sanitized: see X.680 41.4 table 10.
3919 >>> PrintableString().allowable_chars
3920 frozenset([' ', "'", ..., 'z'])
3921 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
3922 PrintableString PrintableString foo*bar
3923 >>> obj.allow_asterisk, obj.allow_ampersand
3927 tag_default = tag_encode(19)
3929 asn1_type_name = "PrintableString"
3930 _allowable_chars = frozenset(
3931 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
3933 _asterisk = frozenset("*".encode("ascii"))
3934 _ampersand = frozenset("&".encode("ascii"))
3946 allow_asterisk=False,
3947 allow_ampersand=False,
3950 :param allow_asterisk: allow asterisk character
3951 :param allow_ampersand: allow ampersand character
3954 self._allowable_chars |= self._asterisk
3956 self._allowable_chars |= self._ampersand
3957 super(PrintableString, self).__init__(
3958 value, bounds, impl, expl, default, optional, _decoded, ctx,
3962 def allow_asterisk(self):
3963 """Is asterisk character allowed?
3965 return self._asterisk <= self._allowable_chars
3968 def allow_ampersand(self):
3969 """Is ampersand character allowed?
3971 return self._ampersand <= self._allowable_chars
3973 def _value_sanitize(self, value):
3974 value = super(PrintableString, self)._value_sanitize(value)
3975 if not frozenset(value) <= self._allowable_chars:
3976 raise DecodeError("non-printable value")
3979 def __getstate__(self):
3980 return PrintableStringState(
3981 *super(PrintableString, self).__getstate__(),
3982 **{"allowable_chars": self._allowable_chars}
3985 def __setstate__(self, state):
3986 super(PrintableString, self).__setstate__(state)
3987 self._allowable_chars = state.allowable_chars
3998 return self.__class__(
4001 (self._bound_min, self._bound_max)
4002 if bounds is None else bounds
4004 impl=self.tag if impl is None else impl,
4005 expl=self._expl if expl is None else expl,
4006 default=self.default if default is None else default,
4007 optional=self.optional if optional is None else optional,
4008 allow_asterisk=self.allow_asterisk,
4009 allow_ampersand=self.allow_ampersand,
4013 class TeletexString(CommonString):
4015 tag_default = tag_encode(20)
4017 asn1_type_name = "TeletexString"
4020 class T61String(TeletexString):
4022 asn1_type_name = "T61String"
4025 class VideotexString(CommonString):
4027 tag_default = tag_encode(21)
4028 encoding = "iso-8859-1"
4029 asn1_type_name = "VideotexString"
4032 class IA5String(CommonString):
4034 tag_default = tag_encode(22)
4036 asn1_type_name = "IA5"
4039 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4040 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4041 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4044 class VisibleString(CommonString):
4046 tag_default = tag_encode(26)
4048 asn1_type_name = "VisibleString"
4051 UTCTimeState = namedtuple(
4053 OctetStringState._fields + ("ber_raw",),
4058 def str_to_time_fractions(value):
4060 year, v = (v // 10**10), (v % 10**10)
4061 month, v = (v // 10**8), (v % 10**8)
4062 day, v = (v // 10**6), (v % 10**6)
4063 hour, v = (v // 10**4), (v % 10**4)
4064 minute, second = (v // 100), (v % 100)
4065 return year, month, day, hour, minute, second
4068 class UTCTime(VisibleString):
4069 """``UTCTime`` datetime type
4071 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4072 UTCTime UTCTime 2017-09-30T22:07:50
4078 datetime.datetime(2017, 9, 30, 22, 7, 50)
4079 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4080 datetime.datetime(1957, 9, 30, 22, 7, 50)
4082 If BER encoded value was met, then ``ber_raw`` attribute will hold
4083 its raw representation.
4087 Pay attention that UTCTime can not hold full year, so all years
4088 having < 50 years are treated as 20xx, 19xx otherwise, according
4089 to X.509 recommendation.
4093 No strict validation of UTC offsets are made, but very crude:
4095 * minutes are not exceeding 60
4096 * offset value is not exceeding 14 hours
4098 __slots__ = ("ber_raw",)
4099 tag_default = tag_encode(23)
4101 asn1_type_name = "UTCTime"
4111 bounds=None, # dummy argument, workability for OctetString.decode
4115 :param value: set the value. Either datetime type, or
4116 :py:class:`pyderasn.UTCTime` object
4117 :param bytes impl: override default tag with ``IMPLICIT`` one
4118 :param bytes expl: override default tag with ``EXPLICIT`` one
4119 :param default: set default value. Type same as in ``value``
4120 :param bool optional: is object ``OPTIONAL`` in sequence
4122 super(UTCTime, self).__init__(
4123 None, None, impl, expl, None, optional, _decoded, ctx,
4127 if value is not None:
4128 self._value, self.ber_raw = self._value_sanitize(value, ctx)
4129 self.ber_encoded = self.ber_raw is not None
4130 if default is not None:
4131 default, _ = self._value_sanitize(default)
4132 self.default = self.__class__(
4137 if self._value is None:
4138 self._value = default
4140 self.optional = optional
4142 def _strptime_bered(self, value):
4143 year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
4146 raise ValueError("no timezone")
4147 year += 2000 if year < 50 else 1900
4148 decoded = datetime(year, month, day, hour, minute)
4150 if value[-1] == "Z":
4154 raise ValueError("invalid UTC offset")
4155 if value[-5] == "-":
4157 elif value[-5] == "+":
4160 raise ValueError("invalid UTC offset")
4161 v = pureint(value[-4:])
4162 offset, v = (60 * (v % 100)), v // 100
4164 raise ValueError("invalid UTC offset minutes")
4166 if offset > 14 * 3600:
4167 raise ValueError("too big UTC offset")
4171 return offset, decoded
4173 raise ValueError("invalid UTC offset seconds")
4174 seconds = pureint(value)
4176 raise ValueError("invalid seconds value")
4177 return offset, decoded + timedelta(seconds=seconds)
4179 def _strptime(self, value):
4180 # datetime.strptime's format: %y%m%d%H%M%SZ
4181 if len(value) != LEN_YYMMDDHHMMSSZ:
4182 raise ValueError("invalid UTCTime length")
4183 if value[-1] != "Z":
4184 raise ValueError("non UTC timezone")
4185 year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
4186 year += 2000 if year < 50 else 1900
4187 return datetime(year, month, day, hour, minute, second)
4189 def _dt_sanitize(self, value):
4190 if value.year < 1950 or value.year > 2049:
4191 raise ValueError("UTCTime can hold only 1950-2049 years")
4192 return value.replace(microsecond=0)
4194 def _value_sanitize(self, value, ctx=None):
4195 if value.__class__ == binary_type:
4197 value_decoded = value.decode("ascii")
4198 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4199 raise DecodeError("invalid UTCTime encoding: %r" % err)
4202 return self._strptime(value_decoded), None
4203 except (TypeError, ValueError) as _err:
4205 if (ctx is not None) and ctx.get("bered", False):
4207 offset, _value = self._strptime_bered(value_decoded)
4208 _value = _value - timedelta(seconds=offset)
4209 return self._dt_sanitize(_value), value
4210 except (TypeError, ValueError, OverflowError) as _err:
4213 "invalid %s format: %r" % (self.asn1_type_name, err),
4214 klass=self.__class__,
4216 if isinstance(value, self.__class__):
4217 return value._value, None
4218 if value.__class__ == datetime:
4219 return self._dt_sanitize(value), None
4220 raise InvalidValueType((self.__class__, datetime))
4222 def _pp_value(self):
4224 value = self._value.isoformat()
4225 if self.ber_encoded:
4226 value += " (%s)" % self.ber_raw
4229 def __unicode__(self):
4231 value = self._value.isoformat()
4232 if self.ber_encoded:
4233 value += " (%s)" % self.ber_raw
4235 return text_type(self._pp_value())
4237 def __getstate__(self):
4238 return UTCTimeState(
4239 *super(UTCTime, self).__getstate__(),
4240 **{"ber_raw": self.ber_raw}
4243 def __setstate__(self, state):
4244 super(UTCTime, self).__setstate__(state)
4245 self.ber_raw = state.ber_raw
4247 def __bytes__(self):
4248 self._assert_ready()
4249 return self._encode_time()
4251 def __eq__(self, their):
4252 if their.__class__ == binary_type:
4253 return self._encode_time() == their
4254 if their.__class__ == datetime:
4255 return self.todatetime() == their
4256 if not isinstance(their, self.__class__):
4259 self._value == their._value and
4260 self.tag == their.tag and
4261 self._expl == their._expl
4264 def _encode_time(self):
4265 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4268 self._assert_ready()
4269 value = self._encode_time()
4270 return b"".join((self.tag, len_encode(len(value)), value))
4272 def todatetime(self):
4276 return pp_console_row(next(self.pps()))
4278 def pps(self, decode_path=()):
4281 asn1_type_name=self.asn1_type_name,
4282 obj_name=self.__class__.__name__,
4283 decode_path=decode_path,
4284 value=self._pp_value(),
4285 optional=self.optional,
4286 default=self == self.default,
4287 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4288 expl=None if self._expl is None else tag_decode(self._expl),
4293 expl_offset=self.expl_offset if self.expled else None,
4294 expl_tlen=self.expl_tlen if self.expled else None,
4295 expl_llen=self.expl_llen if self.expled else None,
4296 expl_vlen=self.expl_vlen if self.expled else None,
4297 expl_lenindef=self.expl_lenindef,
4298 ber_encoded=self.ber_encoded,
4301 for pp in self.pps_lenindef(decode_path):
4305 class GeneralizedTime(UTCTime):
4306 """``GeneralizedTime`` datetime type
4308 This type is similar to :py:class:`pyderasn.UTCTime`.
4310 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4311 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4313 '20170930220750.000123Z'
4314 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4315 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4319 Only microsecond fractions are supported in DER encoding.
4320 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4321 higher precision values.
4325 BER encoded data can loss information (accuracy) during decoding
4326 because of float transformations.
4330 Local times (without explicit timezone specification) are treated
4331 as UTC one, no transformations are made.
4335 Zero year is unsupported.
4338 tag_default = tag_encode(24)
4339 asn1_type_name = "GeneralizedTime"
4341 def _dt_sanitize(self, value):
4344 def _strptime_bered(self, value):
4345 if len(value) < 4 + 3 * 2:
4346 raise ValueError("invalid GeneralizedTime")
4347 year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
4348 decoded = datetime(year, month, day, hour)
4349 offset, value = 0, value[10:]
4351 return offset, decoded
4352 if value[-1] == "Z":
4355 for char, sign in (("-", -1), ("+", 1)):
4356 idx = value.rfind(char)
4359 offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
4360 v = pureint(offset_raw)
4361 if len(offset_raw) == 4:
4362 offset, v = (60 * (v % 100)), v // 100
4364 raise ValueError("invalid UTC offset minutes")
4365 elif len(offset_raw) == 2:
4368 raise ValueError("invalid UTC offset")
4370 if offset > 14 * 3600:
4371 raise ValueError("too big UTC offset")
4375 return offset, decoded
4376 if value[0] in DECIMAL_SIGNS:
4378 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4381 raise ValueError("stripped minutes")
4382 decoded += timedelta(seconds=60 * pureint(value[:2]))
4385 return offset, decoded
4386 if value[0] in DECIMAL_SIGNS:
4388 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4391 raise ValueError("stripped seconds")
4392 decoded += timedelta(seconds=pureint(value[:2]))
4395 return offset, decoded
4396 if value[0] not in DECIMAL_SIGNS:
4397 raise ValueError("invalid format after seconds")
4399 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4402 def _strptime(self, value):
4404 if l == LEN_YYYYMMDDHHMMSSZ:
4405 # datetime.strptime's format: %Y%m%d%H%M%SZ
4406 if value[-1] != "Z":
4407 raise ValueError("non UTC timezone")
4408 return datetime(*str_to_time_fractions(value[:-1]))
4409 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4410 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4411 if value[-1] != "Z":
4412 raise ValueError("non UTC timezone")
4413 if value[14] != ".":
4414 raise ValueError("no fractions separator")
4417 raise ValueError("trailing zero")
4420 raise ValueError("only microsecond fractions are supported")
4421 us = pureint(us + ("0" * (6 - us_len)))
4422 year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
4423 return datetime(year, month, day, hour, minute, second, us)
4424 raise ValueError("invalid GeneralizedTime length")
4426 def _encode_time(self):
4428 encoded = value.strftime("%Y%m%d%H%M%S")
4429 if value.microsecond > 0:
4430 encoded += (".%06d" % value.microsecond).rstrip("0")
4431 return (encoded + "Z").encode("ascii")
4434 class GraphicString(CommonString):
4436 tag_default = tag_encode(25)
4437 encoding = "iso-8859-1"
4438 asn1_type_name = "GraphicString"
4441 class ISO646String(VisibleString):
4443 asn1_type_name = "ISO646String"
4446 class GeneralString(CommonString):
4448 tag_default = tag_encode(27)
4449 encoding = "iso-8859-1"
4450 asn1_type_name = "GeneralString"
4453 class UniversalString(CommonString):
4455 tag_default = tag_encode(28)
4456 encoding = "utf-32-be"
4457 asn1_type_name = "UniversalString"
4460 class BMPString(CommonString):
4462 tag_default = tag_encode(30)
4463 encoding = "utf-16-be"
4464 asn1_type_name = "BMPString"
4467 ChoiceState = namedtuple(
4469 BasicState._fields + ("specs", "value",),
4475 """``CHOICE`` special type
4479 class GeneralName(Choice):
4481 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4482 ("dNSName", IA5String(impl=tag_ctxp(2))),
4485 >>> gn = GeneralName()
4487 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4488 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4489 >>> gn["dNSName"] = IA5String("bar.baz")
4490 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4491 >>> gn["rfc822Name"]
4494 [2] IA5String IA5 bar.baz
4497 >>> gn.value == gn["dNSName"]
4500 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4502 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4503 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4505 __slots__ = ("specs",)
4507 asn1_type_name = "CHOICE"
4520 :param value: set the value. Either ``(choice, value)`` tuple, or
4521 :py:class:`pyderasn.Choice` object
4522 :param bytes impl: can not be set, do **not** use it
4523 :param bytes expl: override default tag with ``EXPLICIT`` one
4524 :param default: set default value. Type same as in ``value``
4525 :param bool optional: is object ``OPTIONAL`` in sequence
4527 if impl is not None:
4528 raise ValueError("no implicit tag allowed for CHOICE")
4529 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4531 schema = getattr(self, "schema", ())
4532 if len(schema) == 0:
4533 raise ValueError("schema must be specified")
4535 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
4538 if value is not None:
4539 self._value = self._value_sanitize(value)
4540 if default is not None:
4541 default_value = self._value_sanitize(default)
4542 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4543 default_obj.specs = self.specs
4544 default_obj._value = default_value
4545 self.default = default_obj
4547 self._value = copy(default_obj._value)
4549 def _value_sanitize(self, value):
4550 if (value.__class__ == tuple) and len(value) == 2:
4552 spec = self.specs.get(choice)
4554 raise ObjUnknown(choice)
4555 if not isinstance(obj, spec.__class__):
4556 raise InvalidValueType((spec,))
4557 return (choice, spec(obj))
4558 if isinstance(value, self.__class__):
4560 raise InvalidValueType((self.__class__, tuple))
4564 return self._value is not None and self._value[1].ready
4568 return self.expl_lenindef or (
4569 (self._value is not None) and
4570 self._value[1].bered
4573 def __getstate__(self):
4590 def __setstate__(self, state):
4591 super(Choice, self).__setstate__(state)
4592 self.specs = state.specs
4593 self._value = state.value
4595 def __eq__(self, their):
4596 if (their.__class__ == tuple) and len(their) == 2:
4597 return self._value == their
4598 if not isinstance(their, self.__class__):
4601 self.specs == their.specs and
4602 self._value == their._value
4612 return self.__class__(
4615 expl=self._expl if expl is None else expl,
4616 default=self.default if default is None else default,
4617 optional=self.optional if optional is None else optional,
4622 self._assert_ready()
4623 return self._value[0]
4627 self._assert_ready()
4628 return self._value[1]
4630 def __getitem__(self, key):
4631 if key not in self.specs:
4632 raise ObjUnknown(key)
4633 if self._value is None:
4635 choice, value = self._value
4640 def __setitem__(self, key, value):
4641 spec = self.specs.get(key)
4643 raise ObjUnknown(key)
4644 if not isinstance(value, spec.__class__):
4645 raise InvalidValueType((spec.__class__,))
4646 self._value = (key, spec(value))
4654 return self._value[1].decoded if self.ready else False
4657 self._assert_ready()
4658 return self._value[1].encode()
4660 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4661 for choice, spec in iteritems(self.specs):
4662 sub_decode_path = decode_path + (choice,)
4668 decode_path=sub_decode_path,
4671 _ctx_immutable=False,
4678 klass=self.__class__,
4679 decode_path=decode_path,
4682 if tag_only: # pragma: no cover
4684 value, tail = spec.decode(
4688 decode_path=sub_decode_path,
4690 _ctx_immutable=False,
4692 obj = self.__class__(
4695 default=self.default,
4696 optional=self.optional,
4697 _decoded=(offset, 0, value.fulllen),
4699 obj._value = (choice, value)
4703 value = pp_console_row(next(self.pps()))
4705 value = "%s[%r]" % (value, self.value)
4708 def pps(self, decode_path=()):
4711 asn1_type_name=self.asn1_type_name,
4712 obj_name=self.__class__.__name__,
4713 decode_path=decode_path,
4714 value=self.choice if self.ready else None,
4715 optional=self.optional,
4716 default=self == self.default,
4717 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4718 expl=None if self._expl is None else tag_decode(self._expl),
4723 expl_lenindef=self.expl_lenindef,
4727 yield self.value.pps(decode_path=decode_path + (self.choice,))
4728 for pp in self.pps_lenindef(decode_path):
4732 class PrimitiveTypes(Choice):
4733 """Predefined ``CHOICE`` for all generic primitive types
4735 It could be useful for general decoding of some unspecified values:
4737 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4738 OCTET STRING 3 bytes 666f6f
4739 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4743 schema = tuple((klass.__name__, klass()) for klass in (
4767 AnyState = namedtuple(
4769 BasicState._fields + ("value", "defined"),
4775 """``ANY`` special type
4777 >>> Any(Integer(-123))
4779 >>> a = Any(OctetString(b"hello world").encode())
4780 ANY 040b68656c6c6f20776f726c64
4781 >>> hexenc(bytes(a))
4782 b'0x040x0bhello world'
4784 __slots__ = ("defined",)
4785 tag_default = tag_encode(0)
4786 asn1_type_name = "ANY"
4796 :param value: set the value. Either any kind of pyderasn's
4797 **ready** object, or bytes. Pay attention that
4798 **no** validation is performed is raw binary value
4800 :param bytes expl: override default tag with ``EXPLICIT`` one
4801 :param bool optional: is object ``OPTIONAL`` in sequence
4803 super(Any, self).__init__(None, expl, None, optional, _decoded)
4804 self._value = None if value is None else self._value_sanitize(value)
4807 def _value_sanitize(self, value):
4808 if value.__class__ == binary_type:
4810 if isinstance(value, self.__class__):
4812 if isinstance(value, Obj):
4813 return value.encode()
4814 raise InvalidValueType((self.__class__, Obj, binary_type))
4818 return self._value is not None
4822 if self.expl_lenindef or self.lenindef:
4824 if self.defined is None:
4826 return self.defined[1].bered
4828 def __getstate__(self):
4845 def __setstate__(self, state):
4846 super(Any, self).__setstate__(state)
4847 self._value = state.value
4848 self.defined = state.defined
4850 def __eq__(self, their):
4851 if their.__class__ == binary_type:
4852 return self._value == their
4853 if issubclass(their.__class__, Any):
4854 return self._value == their._value
4863 return self.__class__(
4865 expl=self._expl if expl is None else expl,
4866 optional=self.optional if optional is None else optional,
4869 def __bytes__(self):
4870 self._assert_ready()
4878 self._assert_ready()
4881 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4883 t, tlen, lv = tag_strip(tlv)
4884 except DecodeError as err:
4885 raise err.__class__(
4887 klass=self.__class__,
4888 decode_path=decode_path,
4892 l, llen, v = len_decode(lv)
4893 except LenIndefForm as err:
4894 if not ctx.get("bered", False):
4895 raise err.__class__(
4897 klass=self.__class__,
4898 decode_path=decode_path,
4901 llen, vlen, v = 1, 0, lv[1:]
4902 sub_offset = offset + tlen + llen
4904 while v[:EOC_LEN].tobytes() != EOC:
4905 chunk, v = Any().decode(
4908 decode_path=decode_path + (str(chunk_i),),
4911 _ctx_immutable=False,
4913 vlen += chunk.tlvlen
4914 sub_offset += chunk.tlvlen
4916 tlvlen = tlen + llen + vlen + EOC_LEN
4917 obj = self.__class__(
4918 value=tlv[:tlvlen].tobytes(),
4920 optional=self.optional,
4921 _decoded=(offset, 0, tlvlen),
4924 obj.tag = t.tobytes()
4925 return obj, v[EOC_LEN:]
4926 except DecodeError as err:
4927 raise err.__class__(
4929 klass=self.__class__,
4930 decode_path=decode_path,
4934 raise NotEnoughData(
4935 "encoded length is longer than data",
4936 klass=self.__class__,
4937 decode_path=decode_path,
4940 tlvlen = tlen + llen + l
4941 v, tail = tlv[:tlvlen], v[l:]
4942 obj = self.__class__(
4945 optional=self.optional,
4946 _decoded=(offset, 0, tlvlen),
4948 obj.tag = t.tobytes()
4952 return pp_console_row(next(self.pps()))
4954 def pps(self, decode_path=()):
4957 asn1_type_name=self.asn1_type_name,
4958 obj_name=self.__class__.__name__,
4959 decode_path=decode_path,
4960 blob=self._value if self.ready else None,
4961 optional=self.optional,
4962 default=self == self.default,
4963 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4964 expl=None if self._expl is None else tag_decode(self._expl),
4969 expl_offset=self.expl_offset if self.expled else None,
4970 expl_tlen=self.expl_tlen if self.expled else None,
4971 expl_llen=self.expl_llen if self.expled else None,
4972 expl_vlen=self.expl_vlen if self.expled else None,
4973 expl_lenindef=self.expl_lenindef,
4974 lenindef=self.lenindef,
4977 defined_by, defined = self.defined or (None, None)
4978 if defined_by is not None:
4980 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4982 for pp in self.pps_lenindef(decode_path):
4986 ########################################################################
4987 # ASN.1 constructed types
4988 ########################################################################
4990 def get_def_by_path(defines_by_path, sub_decode_path):
4991 """Get define by decode path
4993 for path, define in defines_by_path:
4994 if len(path) != len(sub_decode_path):
4996 for p1, p2 in zip(path, sub_decode_path):
4997 if (not p1 is any) and (p1 != p2):
5003 def abs_decode_path(decode_path, rel_path):
5004 """Create an absolute decode path from current and relative ones
5006 :param decode_path: current decode path, starting point. Tuple of strings
5007 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5008 If first tuple's element is "/", then treat it as
5009 an absolute path, ignoring ``decode_path`` as
5010 starting point. Also this tuple can contain ".."
5011 elements, stripping the leading element from
5014 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5015 ("foo", "bar", "baz", "whatever")
5016 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5018 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5021 if rel_path[0] == "/":
5023 if rel_path[0] == "..":
5024 return abs_decode_path(decode_path[:-1], rel_path[1:])
5025 return decode_path + rel_path
5028 SequenceState = namedtuple(
5030 BasicState._fields + ("specs", "value",),
5035 class Sequence(Obj):
5036 """``SEQUENCE`` structure type
5038 You have to make specification of sequence::
5040 class Extension(Sequence):
5042 ("extnID", ObjectIdentifier()),
5043 ("critical", Boolean(default=False)),
5044 ("extnValue", OctetString()),
5047 Then, you can work with it as with dictionary.
5049 >>> ext = Extension()
5050 >>> Extension().specs
5052 ('extnID', OBJECT IDENTIFIER),
5053 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5054 ('extnValue', OCTET STRING),
5056 >>> ext["extnID"] = "1.2.3"
5057 Traceback (most recent call last):
5058 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5059 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5061 You can determine if sequence is ready to be encoded:
5066 Traceback (most recent call last):
5067 pyderasn.ObjNotReady: object is not ready: extnValue
5068 >>> ext["extnValue"] = OctetString(b"foobar")
5072 Value you want to assign, must have the same **type** as in
5073 corresponding specification, but it can have different tags,
5074 optional/default attributes -- they will be taken from specification
5077 class TBSCertificate(Sequence):
5079 ("version", Version(expl=tag_ctxc(0), default="v1")),
5082 >>> tbs = TBSCertificate()
5083 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5085 Assign ``None`` to remove value from sequence.
5087 You can set values in Sequence during its initialization:
5089 >>> AlgorithmIdentifier((
5090 ("algorithm", ObjectIdentifier("1.2.3")),
5091 ("parameters", Any(Null()))
5093 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5095 You can determine if value exists/set in the sequence and take its value:
5097 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5100 OBJECT IDENTIFIER 1.2.3
5102 But pay attention that if value has default, then it won't be (not
5103 in) in the sequence (because ``DEFAULT`` must not be encoded in
5104 DER), but you can read its value:
5106 >>> "critical" in ext, ext["critical"]
5107 (False, BOOLEAN False)
5108 >>> ext["critical"] = Boolean(True)
5109 >>> "critical" in ext, ext["critical"]
5110 (True, BOOLEAN True)
5112 All defaulted values are always optional.
5114 .. _allow_default_values_ctx:
5116 DER prohibits default value encoding and will raise an error if
5117 default value is unexpectedly met during decode.
5118 If :ref:`bered <bered_ctx>` context option is set, then no error
5119 will be raised, but ``bered`` attribute set. You can disable strict
5120 defaulted values existence validation by setting
5121 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5123 Two sequences are equal if they have equal specification (schema),
5124 implicit/explicit tagging and the same values.
5126 __slots__ = ("specs",)
5127 tag_default = tag_encode(form=TagFormConstructed, num=16)
5128 asn1_type_name = "SEQUENCE"
5140 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5142 schema = getattr(self, "schema", ())
5144 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
5147 if value is not None:
5148 if issubclass(value.__class__, Sequence):
5149 self._value = value._value
5150 elif hasattr(value, "__iter__"):
5151 for seq_key, seq_value in value:
5152 self[seq_key] = seq_value
5154 raise InvalidValueType((Sequence,))
5155 if default is not None:
5156 if not issubclass(default.__class__, Sequence):
5157 raise InvalidValueType((Sequence,))
5158 default_value = default._value
5159 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5160 default_obj.specs = self.specs
5161 default_obj._value = default_value
5162 self.default = default_obj
5164 self._value = copy(default_obj._value)
5168 for name, spec in iteritems(self.specs):
5169 value = self._value.get(name)
5180 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5182 return any(value.bered for value in itervalues(self._value))
5184 def __getstate__(self):
5185 return SequenceState(
5198 {k: copy(v) for k, v in iteritems(self._value)},
5201 def __setstate__(self, state):
5202 super(Sequence, self).__setstate__(state)
5203 self.specs = state.specs
5204 self._value = state.value
5206 def __eq__(self, their):
5207 if not isinstance(their, self.__class__):
5210 self.specs == their.specs and
5211 self.tag == their.tag and
5212 self._expl == their._expl and
5213 self._value == their._value
5224 return self.__class__(
5227 impl=self.tag if impl is None else impl,
5228 expl=self._expl if expl is None else expl,
5229 default=self.default if default is None else default,
5230 optional=self.optional if optional is None else optional,
5233 def __contains__(self, key):
5234 return key in self._value
5236 def __setitem__(self, key, value):
5237 spec = self.specs.get(key)
5239 raise ObjUnknown(key)
5241 self._value.pop(key, None)
5243 if not isinstance(value, spec.__class__):
5244 raise InvalidValueType((spec.__class__,))
5245 value = spec(value=value)
5246 if spec.default is not None and value == spec.default:
5247 self._value.pop(key, None)
5249 self._value[key] = value
5251 def __getitem__(self, key):
5252 value = self._value.get(key)
5253 if value is not None:
5255 spec = self.specs.get(key)
5257 raise ObjUnknown(key)
5258 if spec.default is not None:
5262 def _values_for_encoding(self):
5263 for name, spec in iteritems(self.specs):
5264 value = self._value.get(name)
5268 raise ObjNotReady(name)
5272 v = b"".join(v.encode() for v in self._values_for_encoding())
5273 return b"".join((self.tag, len_encode(len(v)), v))
5275 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5277 t, tlen, lv = tag_strip(tlv)
5278 except DecodeError as err:
5279 raise err.__class__(
5281 klass=self.__class__,
5282 decode_path=decode_path,
5287 klass=self.__class__,
5288 decode_path=decode_path,
5291 if tag_only: # pragma: no cover
5294 ctx_bered = ctx.get("bered", False)
5296 l, llen, v = len_decode(lv)
5297 except LenIndefForm as err:
5299 raise err.__class__(
5301 klass=self.__class__,
5302 decode_path=decode_path,
5305 l, llen, v = 0, 1, lv[1:]
5307 except DecodeError as err:
5308 raise err.__class__(
5310 klass=self.__class__,
5311 decode_path=decode_path,
5315 raise NotEnoughData(
5316 "encoded length is longer than data",
5317 klass=self.__class__,
5318 decode_path=decode_path,
5322 v, tail = v[:l], v[l:]
5324 sub_offset = offset + tlen + llen
5327 ctx_allow_default_values = ctx.get("allow_default_values", False)
5328 for name, spec in iteritems(self.specs):
5329 if spec.optional and (
5330 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5334 sub_decode_path = decode_path + (name,)
5336 value, v_tail = spec.decode(
5340 decode_path=sub_decode_path,
5342 _ctx_immutable=False,
5344 except TagMismatch as err:
5345 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5349 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5350 if defined is not None:
5351 defined_by, defined_spec = defined
5352 if issubclass(value.__class__, SequenceOf):
5353 for i, _value in enumerate(value):
5354 sub_sub_decode_path = sub_decode_path + (
5356 DecodePathDefBy(defined_by),
5358 defined_value, defined_tail = defined_spec.decode(
5359 memoryview(bytes(_value)),
5361 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5362 if value.expled else (value.tlen + value.llen)
5365 decode_path=sub_sub_decode_path,
5367 _ctx_immutable=False,
5369 if len(defined_tail) > 0:
5372 klass=self.__class__,
5373 decode_path=sub_sub_decode_path,
5376 _value.defined = (defined_by, defined_value)
5378 defined_value, defined_tail = defined_spec.decode(
5379 memoryview(bytes(value)),
5381 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5382 if value.expled else (value.tlen + value.llen)
5385 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5387 _ctx_immutable=False,
5389 if len(defined_tail) > 0:
5392 klass=self.__class__,
5393 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5396 value.defined = (defined_by, defined_value)
5398 value_len = value.fulllen
5400 sub_offset += value_len
5402 if spec.default is not None and value == spec.default:
5403 if ctx_bered or ctx_allow_default_values:
5407 "DEFAULT value met",
5408 klass=self.__class__,
5409 decode_path=sub_decode_path,
5412 values[name] = value
5414 spec_defines = getattr(spec, "defines", ())
5415 if len(spec_defines) == 0:
5416 defines_by_path = ctx.get("defines_by_path", ())
5417 if len(defines_by_path) > 0:
5418 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5419 if spec_defines is not None and len(spec_defines) > 0:
5420 for rel_path, schema in spec_defines:
5421 defined = schema.get(value, None)
5422 if defined is not None:
5423 ctx.setdefault("_defines", []).append((
5424 abs_decode_path(sub_decode_path[:-1], rel_path),
5428 if v[:EOC_LEN].tobytes() != EOC:
5431 klass=self.__class__,
5432 decode_path=decode_path,
5440 klass=self.__class__,
5441 decode_path=decode_path,
5444 obj = self.__class__(
5448 default=self.default,
5449 optional=self.optional,
5450 _decoded=(offset, llen, vlen),
5453 obj.lenindef = lenindef
5454 obj.ber_encoded = ber_encoded
5458 value = pp_console_row(next(self.pps()))
5460 for name in self.specs:
5461 _value = self._value.get(name)
5464 cols.append("%s: %s" % (name, repr(_value)))
5465 return "%s[%s]" % (value, "; ".join(cols))
5467 def pps(self, decode_path=()):
5470 asn1_type_name=self.asn1_type_name,
5471 obj_name=self.__class__.__name__,
5472 decode_path=decode_path,
5473 optional=self.optional,
5474 default=self == self.default,
5475 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5476 expl=None if self._expl is None else tag_decode(self._expl),
5481 expl_offset=self.expl_offset if self.expled else None,
5482 expl_tlen=self.expl_tlen if self.expled else None,
5483 expl_llen=self.expl_llen if self.expled else None,
5484 expl_vlen=self.expl_vlen if self.expled else None,
5485 expl_lenindef=self.expl_lenindef,
5486 lenindef=self.lenindef,
5487 ber_encoded=self.ber_encoded,
5490 for name in self.specs:
5491 value = self._value.get(name)
5494 yield value.pps(decode_path=decode_path + (name,))
5495 for pp in self.pps_lenindef(decode_path):
5499 class Set(Sequence):
5500 """``SET`` structure type
5502 Its usage is identical to :py:class:`pyderasn.Sequence`.
5504 .. _allow_unordered_set_ctx:
5506 DER prohibits unordered values encoding and will raise an error
5507 during decode. If :ref:`bered <bered_ctx>` context option is set,
5508 then no error will occur. Also you can disable strict values
5509 ordering check by setting ``"allow_unordered_set": True``
5510 :ref:`context <ctx>` option.
5513 tag_default = tag_encode(form=TagFormConstructed, num=17)
5514 asn1_type_name = "SET"
5517 raws = [v.encode() for v in self._values_for_encoding()]
5520 return b"".join((self.tag, len_encode(len(v)), v))
5522 def _specs_items(self):
5523 return iteritems(self.specs)
5525 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5527 t, tlen, lv = tag_strip(tlv)
5528 except DecodeError as err:
5529 raise err.__class__(
5531 klass=self.__class__,
5532 decode_path=decode_path,
5537 klass=self.__class__,
5538 decode_path=decode_path,
5544 ctx_bered = ctx.get("bered", False)
5546 l, llen, v = len_decode(lv)
5547 except LenIndefForm as err:
5549 raise err.__class__(
5551 klass=self.__class__,
5552 decode_path=decode_path,
5555 l, llen, v = 0, 1, lv[1:]
5557 except DecodeError as err:
5558 raise err.__class__(
5560 klass=self.__class__,
5561 decode_path=decode_path,
5565 raise NotEnoughData(
5566 "encoded length is longer than data",
5567 klass=self.__class__,
5571 v, tail = v[:l], v[l:]
5573 sub_offset = offset + tlen + llen
5576 ctx_allow_default_values = ctx.get("allow_default_values", False)
5577 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5578 value_prev = memoryview(v[:0])
5581 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5583 for name, spec in self._specs_items():
5584 sub_decode_path = decode_path + (name,)
5590 decode_path=sub_decode_path,
5593 _ctx_immutable=False,
5600 klass=self.__class__,
5601 decode_path=decode_path,
5604 value, v_tail = spec.decode(
5608 decode_path=sub_decode_path,
5610 _ctx_immutable=False,
5612 value_len = value.fulllen
5613 if value_prev.tobytes() > v[:value_len].tobytes():
5614 if ctx_bered or ctx_allow_unordered_set:
5618 "unordered " + self.asn1_type_name,
5619 klass=self.__class__,
5620 decode_path=sub_decode_path,
5623 if spec.default is None or value != spec.default:
5625 elif ctx_bered or ctx_allow_default_values:
5629 "DEFAULT value met",
5630 klass=self.__class__,
5631 decode_path=sub_decode_path,
5634 values[name] = value
5635 value_prev = v[:value_len]
5636 sub_offset += value_len
5639 obj = self.__class__(
5643 default=self.default,
5644 optional=self.optional,
5645 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5648 if v[:EOC_LEN].tobytes() != EOC:
5651 klass=self.__class__,
5652 decode_path=decode_path,
5658 for name, spec in iteritems(self.specs):
5659 if name not in values and not spec.optional:
5661 "%s value is not ready" % name,
5662 klass=self.__class__,
5663 decode_path=decode_path,
5666 obj.ber_encoded = ber_encoded
5670 SequenceOfState = namedtuple(
5672 BasicState._fields + ("spec", "value", "bound_min", "bound_max"),
5677 class SequenceOf(Obj):
5678 """``SEQUENCE OF`` sequence type
5680 For that kind of type you must specify the object it will carry on
5681 (bounds are for example here, not required)::
5683 class Ints(SequenceOf):
5688 >>> ints.append(Integer(123))
5689 >>> ints.append(Integer(234))
5691 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5692 >>> [int(i) for i in ints]
5694 >>> ints.append(Integer(345))
5695 Traceback (most recent call last):
5696 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5699 >>> ints[1] = Integer(345)
5701 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5703 Also you can initialize sequence with preinitialized values:
5705 >>> ints = Ints([Integer(123), Integer(234)])
5707 __slots__ = ("spec", "_bound_min", "_bound_max")
5708 tag_default = tag_encode(form=TagFormConstructed, num=16)
5709 asn1_type_name = "SEQUENCE OF"
5722 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5724 schema = getattr(self, "schema", None)
5726 raise ValueError("schema must be specified")
5728 self._bound_min, self._bound_max = getattr(
5732 ) if bounds is None else bounds
5734 if value is not None:
5735 self._value = self._value_sanitize(value)
5736 if default is not None:
5737 default_value = self._value_sanitize(default)
5738 default_obj = self.__class__(
5743 default_obj._value = default_value
5744 self.default = default_obj
5746 self._value = copy(default_obj._value)
5748 def _value_sanitize(self, value):
5749 if issubclass(value.__class__, SequenceOf):
5750 value = value._value
5751 elif hasattr(value, "__iter__"):
5754 raise InvalidValueType((self.__class__, iter))
5755 if not self._bound_min <= len(value) <= self._bound_max:
5756 raise BoundsError(self._bound_min, len(value), self._bound_max)
5758 if not isinstance(v, self.spec.__class__):
5759 raise InvalidValueType((self.spec.__class__,))
5764 return all(v.ready for v in self._value)
5768 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5770 return any(v.bered for v in self._value)
5772 def __getstate__(self):
5773 return SequenceOfState(
5786 [copy(v) for v in self._value],
5791 def __setstate__(self, state):
5792 super(SequenceOf, self).__setstate__(state)
5793 self.spec = state.spec
5794 self._value = state.value
5795 self._bound_min = state.bound_min
5796 self._bound_max = state.bound_max
5798 def __eq__(self, their):
5799 if isinstance(their, self.__class__):
5801 self.spec == their.spec and
5802 self.tag == their.tag and
5803 self._expl == their._expl and
5804 self._value == their._value
5806 if hasattr(their, "__iter__"):
5807 return self._value == list(their)
5819 return self.__class__(
5823 (self._bound_min, self._bound_max)
5824 if bounds is None else bounds
5826 impl=self.tag if impl is None else impl,
5827 expl=self._expl if expl is None else expl,
5828 default=self.default if default is None else default,
5829 optional=self.optional if optional is None else optional,
5832 def __contains__(self, key):
5833 return key in self._value
5835 def append(self, value):
5836 if not isinstance(value, self.spec.__class__):
5837 raise InvalidValueType((self.spec.__class__,))
5838 if len(self._value) + 1 > self._bound_max:
5841 len(self._value) + 1,
5844 self._value.append(value)
5847 self._assert_ready()
5848 return iter(self._value)
5851 self._assert_ready()
5852 return len(self._value)
5854 def __setitem__(self, key, value):
5855 if not isinstance(value, self.spec.__class__):
5856 raise InvalidValueType((self.spec.__class__,))
5857 self._value[key] = self.spec(value=value)
5859 def __getitem__(self, key):
5860 return self._value[key]
5862 def _values_for_encoding(self):
5863 return iter(self._value)
5866 v = b"".join(v.encode() for v in self._values_for_encoding())
5867 return b"".join((self.tag, len_encode(len(v)), v))
5869 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5871 t, tlen, lv = tag_strip(tlv)
5872 except DecodeError as err:
5873 raise err.__class__(
5875 klass=self.__class__,
5876 decode_path=decode_path,
5881 klass=self.__class__,
5882 decode_path=decode_path,
5888 ctx_bered = ctx.get("bered", False)
5890 l, llen, v = len_decode(lv)
5891 except LenIndefForm as err:
5893 raise err.__class__(
5895 klass=self.__class__,
5896 decode_path=decode_path,
5899 l, llen, v = 0, 1, lv[1:]
5901 except DecodeError as err:
5902 raise err.__class__(
5904 klass=self.__class__,
5905 decode_path=decode_path,
5909 raise NotEnoughData(
5910 "encoded length is longer than data",
5911 klass=self.__class__,
5912 decode_path=decode_path,
5916 v, tail = v[:l], v[l:]
5918 sub_offset = offset + tlen + llen
5920 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5921 value_prev = memoryview(v[:0])
5925 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5927 sub_decode_path = decode_path + (str(len(_value)),)
5928 value, v_tail = spec.decode(
5932 decode_path=sub_decode_path,
5934 _ctx_immutable=False,
5936 value_len = value.fulllen
5938 if value_prev.tobytes() > v[:value_len].tobytes():
5939 if ctx_bered or ctx_allow_unordered_set:
5943 "unordered " + self.asn1_type_name,
5944 klass=self.__class__,
5945 decode_path=sub_decode_path,
5948 value_prev = v[:value_len]
5949 _value.append(value)
5950 sub_offset += value_len
5954 obj = self.__class__(
5957 bounds=(self._bound_min, self._bound_max),
5960 default=self.default,
5961 optional=self.optional,
5962 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5964 except BoundsError as err:
5967 klass=self.__class__,
5968 decode_path=decode_path,
5972 if v[:EOC_LEN].tobytes() != EOC:
5975 klass=self.__class__,
5976 decode_path=decode_path,
5981 obj.ber_encoded = ber_encoded
5986 pp_console_row(next(self.pps())),
5987 ", ".join(repr(v) for v in self._value),
5990 def pps(self, decode_path=()):
5993 asn1_type_name=self.asn1_type_name,
5994 obj_name=self.__class__.__name__,
5995 decode_path=decode_path,
5996 optional=self.optional,
5997 default=self == self.default,
5998 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5999 expl=None if self._expl is None else tag_decode(self._expl),
6004 expl_offset=self.expl_offset if self.expled else None,
6005 expl_tlen=self.expl_tlen if self.expled else None,
6006 expl_llen=self.expl_llen if self.expled else None,
6007 expl_vlen=self.expl_vlen if self.expled else None,
6008 expl_lenindef=self.expl_lenindef,
6009 lenindef=self.lenindef,
6010 ber_encoded=self.ber_encoded,
6013 for i, value in enumerate(self._value):
6014 yield value.pps(decode_path=decode_path + (str(i),))
6015 for pp in self.pps_lenindef(decode_path):
6019 class SetOf(SequenceOf):
6020 """``SET OF`` sequence type
6022 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6025 tag_default = tag_encode(form=TagFormConstructed, num=17)
6026 asn1_type_name = "SET OF"
6029 raws = [v.encode() for v in self._values_for_encoding()]
6032 return b"".join((self.tag, len_encode(len(v)), v))
6034 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6035 return super(SetOf, self)._decode(
6041 ordering_check=True,
6045 def obj_by_path(pypath): # pragma: no cover
6046 """Import object specified as string Python path
6048 Modules must be separated from classes/functions with ``:``.
6050 >>> obj_by_path("foo.bar:Baz")
6051 <class 'foo.bar.Baz'>
6052 >>> obj_by_path("foo.bar:Baz.boo")
6053 <classmethod 'foo.bar.Baz.boo'>
6055 mod, objs = pypath.rsplit(":", 1)
6056 from importlib import import_module
6057 obj = import_module(mod)
6058 for obj_name in objs.split("."):
6059 obj = getattr(obj, obj_name)
6063 def generic_decoder(): # pragma: no cover
6064 # All of this below is a big hack with self references
6065 choice = PrimitiveTypes()
6066 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6067 choice.specs["SetOf"] = SetOf(schema=choice)
6068 for i in six_xrange(31):
6069 choice.specs["SequenceOf%d" % i] = SequenceOf(
6073 choice.specs["Any"] = Any()
6075 # Class name equals to type name, to omit it from output
6076 class SEQUENCEOF(SequenceOf):
6084 with_decode_path=False,
6085 decode_path_only=(),
6087 def _pprint_pps(pps):
6089 if hasattr(pp, "_fields"):
6091 decode_path_only != () and
6092 pp.decode_path[:len(decode_path_only)] != decode_path_only
6095 if pp.asn1_type_name == Choice.asn1_type_name:
6097 pp_kwargs = pp._asdict()
6098 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6099 pp = _pp(**pp_kwargs)
6100 yield pp_console_row(
6105 with_colours=with_colours,
6106 with_decode_path=with_decode_path,
6107 decode_path_len_decrease=len(decode_path_only),
6109 for row in pp_console_blob(
6111 decode_path_len_decrease=len(decode_path_only),
6115 for row in _pprint_pps(pp):
6117 return "\n".join(_pprint_pps(obj.pps()))
6118 return SEQUENCEOF(), pprint_any
6121 def main(): # pragma: no cover
6123 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6124 parser.add_argument(
6128 help="Skip that number of bytes from the beginning",
6130 parser.add_argument(
6132 help="Python paths to dictionary with OIDs, comma separated",
6134 parser.add_argument(
6136 help="Python path to schema definition to use",
6138 parser.add_argument(
6139 "--defines-by-path",
6140 help="Python path to decoder's defines_by_path",
6142 parser.add_argument(
6144 action="store_true",
6145 help="Disallow BER encoding",
6147 parser.add_argument(
6148 "--print-decode-path",
6149 action="store_true",
6150 help="Print decode paths",
6152 parser.add_argument(
6153 "--decode-path-only",
6154 help="Print only specified decode path",
6156 parser.add_argument(
6158 action="store_true",
6159 help="Allow explicit tag out-of-bound",
6161 parser.add_argument(
6163 type=argparse.FileType("rb"),
6164 help="Path to DER file you want to decode",
6166 args = parser.parse_args()
6167 args.DERFile.seek(args.skip)
6168 der = memoryview(args.DERFile.read())
6169 args.DERFile.close()
6171 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6172 if args.oids else ()
6175 schema = obj_by_path(args.schema)
6176 from functools import partial
6177 pprinter = partial(pprint, big_blobs=True)
6179 schema, pprinter = generic_decoder()
6181 "bered": not args.nobered,
6182 "allow_expl_oob": args.allow_expl_oob,
6184 if args.defines_by_path is not None:
6185 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6186 obj, tail = schema().decode(der, ctx=ctx)
6187 from os import environ
6191 with_colours=environ.get("NO_COLOR") is None,
6192 with_decode_path=args.print_decode_path,
6194 () if args.decode_path_only is None else
6195 tuple(args.decode_path_only.split(":"))
6199 print("\nTrailing data: %s" % hexenc(tail))
6202 if __name__ == "__main__":