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 @add_metaclass(AutoAddSlots)
1082 """Common ASN.1 object class
1084 All ASN.1 types are inherited from it. It has metaclass that
1085 automatically adds ``__slots__`` to all inherited classes.
1109 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1110 self._expl = getattr(self, "expl", None) if expl is None else expl
1111 if self.tag != self.tag_default and self._expl is not None:
1112 raise ValueError("implicit and explicit tags can not be set simultaneously")
1113 if default is not None:
1115 self.optional = optional
1116 self.offset, self.llen, self.vlen = _decoded
1118 self.expl_lenindef = False
1119 self.lenindef = False
1120 self.ber_encoded = False
1123 def ready(self): # pragma: no cover
1124 """Is object ready to be encoded?
1126 raise NotImplementedError()
1128 def _assert_ready(self):
1130 raise ObjNotReady(self.__class__.__name__)
1134 """Is either object or any elements inside is BER encoded?
1136 return self.expl_lenindef or self.lenindef or self.ber_encoded
1140 """Is object decoded?
1142 return (self.llen + self.vlen) > 0
1144 def __getstate__(self): # pragma: no cover
1145 """Used for making safe to be mutable pickleable copies
1147 raise NotImplementedError()
1149 def __setstate__(self, state):
1150 if state.version != __version__:
1151 raise ValueError("data is pickled by different PyDERASN version")
1152 self.tag = self.tag_default
1156 self.optional = False
1160 self.expl_lenindef = False
1161 self.lenindef = False
1162 self.ber_encoded = False
1166 """See :ref:`decoding`
1168 return len(self.tag)
1172 """See :ref:`decoding`
1174 return self.tlen + self.llen + self.vlen
1176 def __str__(self): # pragma: no cover
1177 return self.__bytes__() if PY2 else self.__unicode__()
1179 def __ne__(self, their):
1180 return not(self == their)
1182 def __gt__(self, their): # pragma: no cover
1183 return not(self < their)
1185 def __le__(self, their): # pragma: no cover
1186 return (self == their) or (self < their)
1188 def __ge__(self, their): # pragma: no cover
1189 return (self == their) or (self > their)
1191 def _encode(self): # pragma: no cover
1192 raise NotImplementedError()
1194 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1195 raise NotImplementedError()
1198 """Encode the structure
1200 :returns: DER representation
1202 raw = self._encode()
1203 if self._expl is None:
1205 return b"".join((self._expl, len_encode(len(raw)), raw))
1207 def hexencode(self):
1208 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1210 return hexenc(self.encode())
1220 _ctx_immutable=True,
1224 :param data: either binary or memoryview
1225 :param int offset: initial data's offset
1226 :param bool leavemm: do we need to leave memoryview of remaining
1227 data as is, or convert it to bytes otherwise
1228 :param ctx: optional :ref:`context <ctx>` governing decoding process
1229 :param tag_only: decode only the tag, without length and contents
1230 (used only in Choice and Set structures, trying to
1231 determine if tag satisfies the schema)
1232 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1234 :returns: (Obj, remaining data)
1236 .. seealso:: :ref:`decoding`
1240 elif _ctx_immutable:
1242 tlv = memoryview(data)
1243 if self._expl is None:
1244 result = self._decode(
1247 decode_path=decode_path,
1256 t, tlen, lv = tag_strip(tlv)
1257 except DecodeError as err:
1258 raise err.__class__(
1260 klass=self.__class__,
1261 decode_path=decode_path,
1266 klass=self.__class__,
1267 decode_path=decode_path,
1271 l, llen, v = len_decode(lv)
1272 except LenIndefForm as err:
1273 if not ctx.get("bered", False):
1274 raise err.__class__(
1276 klass=self.__class__,
1277 decode_path=decode_path,
1281 offset += tlen + llen
1282 result = self._decode(
1285 decode_path=decode_path,
1289 if tag_only: # pragma: no cover
1292 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1293 if eoc_expected.tobytes() != EOC:
1296 klass=self.__class__,
1297 decode_path=decode_path,
1301 obj.expl_lenindef = True
1302 except DecodeError as err:
1303 raise err.__class__(
1305 klass=self.__class__,
1306 decode_path=decode_path,
1311 raise NotEnoughData(
1312 "encoded length is longer than data",
1313 klass=self.__class__,
1314 decode_path=decode_path,
1317 result = self._decode(
1319 offset=offset + tlen + llen,
1320 decode_path=decode_path,
1324 if tag_only: # pragma: no cover
1327 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1329 "explicit tag out-of-bound, longer than data",
1330 klass=self.__class__,
1331 decode_path=decode_path,
1334 return obj, (tail if leavemm else tail.tobytes())
1336 def decod(self, data, offset=0, decode_path=(), ctx=None):
1337 """Decode the data, check that tail is empty
1339 :raises ExceedingData: if tail is not empty
1341 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1342 (decode without tail) that also checks that there is no
1345 obj, tail = self.decode(
1348 decode_path=decode_path,
1353 raise ExceedingData(len(tail))
1356 def hexdecode(self, data, *args, **kwargs):
1357 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1359 return self.decode(hexdec(data), *args, **kwargs)
1361 def hexdecod(self, data, *args, **kwargs):
1362 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1364 return self.decod(hexdec(data), *args, **kwargs)
1368 """See :ref:`decoding`
1370 return self._expl is not None
1374 """See :ref:`decoding`
1379 def expl_tlen(self):
1380 """See :ref:`decoding`
1382 return len(self._expl)
1385 def expl_llen(self):
1386 """See :ref:`decoding`
1388 if self.expl_lenindef:
1390 return len(len_encode(self.tlvlen))
1393 def expl_offset(self):
1394 """See :ref:`decoding`
1396 return self.offset - self.expl_tlen - self.expl_llen
1399 def expl_vlen(self):
1400 """See :ref:`decoding`
1405 def expl_tlvlen(self):
1406 """See :ref:`decoding`
1408 return self.expl_tlen + self.expl_llen + self.expl_vlen
1411 def fulloffset(self):
1412 """See :ref:`decoding`
1414 return self.expl_offset if self.expled else self.offset
1418 """See :ref:`decoding`
1420 return self.expl_tlvlen if self.expled else self.tlvlen
1422 def pps_lenindef(self, decode_path):
1423 if self.lenindef and not (
1424 getattr(self, "defined", None) is not None and
1425 self.defined[1].lenindef
1428 asn1_type_name="EOC",
1430 decode_path=decode_path,
1432 self.offset + self.tlvlen -
1433 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1441 if self.expl_lenindef:
1443 asn1_type_name="EOC",
1444 obj_name="EXPLICIT",
1445 decode_path=decode_path,
1446 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1455 class DecodePathDefBy(object):
1456 """DEFINED BY representation inside decode path
1458 __slots__ = ("defined_by",)
1460 def __init__(self, defined_by):
1461 self.defined_by = defined_by
1463 def __ne__(self, their):
1464 return not(self == their)
1466 def __eq__(self, their):
1467 if not isinstance(their, self.__class__):
1469 return self.defined_by == their.defined_by
1472 return "DEFINED BY " + str(self.defined_by)
1475 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1478 ########################################################################
1480 ########################################################################
1482 PP = namedtuple("PP", (
1505 ), **NAMEDTUPLE_KWARGS)
1510 asn1_type_name="unknown",
1527 expl_lenindef=False,
1558 def _colourize(what, colour, with_colours, attrs=("bold",)):
1559 return colored(what, colour, attrs=attrs) if with_colours else what
1562 def colonize_hex(hexed):
1563 """Separate hexadecimal string with colons
1565 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1574 with_decode_path=False,
1575 decode_path_len_decrease=0,
1582 " " if pp.expl_offset is None else
1583 ("-%d" % (pp.offset - pp.expl_offset))
1585 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1587 col = _colourize(col, "red", with_colours, ())
1588 col += _colourize("B", "red", with_colours) if pp.bered else " "
1590 col = "[%d,%d,%4d]%s" % (
1594 LENINDEF_PP_CHAR if pp.lenindef else " "
1596 col = _colourize(col, "green", with_colours, ())
1598 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1599 if decode_path_len > 0:
1600 cols.append(" ." * decode_path_len)
1601 ent = pp.decode_path[-1]
1602 if isinstance(ent, DecodePathDefBy):
1603 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1604 value = str(ent.defined_by)
1607 len(oid_maps) > 0 and
1608 ent.defined_by.asn1_type_name ==
1609 ObjectIdentifier.asn1_type_name
1611 for oid_map in oid_maps:
1612 oid_name = oid_map.get(value)
1613 if oid_name is not None:
1614 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1616 if oid_name is None:
1617 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1619 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1620 if pp.expl is not None:
1621 klass, _, num = pp.expl
1622 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1623 cols.append(_colourize(col, "blue", with_colours))
1624 if pp.impl is not None:
1625 klass, _, num = pp.impl
1626 col = "[%s%d]" % (TagClassReprs[klass], num)
1627 cols.append(_colourize(col, "blue", with_colours))
1628 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1629 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1631 cols.append(_colourize("BER", "red", with_colours))
1632 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1633 if pp.value is not None:
1635 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1637 len(oid_maps) > 0 and
1638 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1640 for oid_map in oid_maps:
1641 oid_name = oid_map.get(value)
1642 if oid_name is not None:
1643 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1645 if pp.asn1_type_name == Integer.asn1_type_name:
1646 hex_repr = hex(int(pp.obj._value))[2:].upper()
1647 if len(hex_repr) % 2 != 0:
1648 hex_repr = "0" + hex_repr
1649 cols.append(_colourize(
1650 "(%s)" % colonize_hex(hex_repr),
1655 if pp.blob.__class__ == binary_type:
1656 cols.append(hexenc(pp.blob))
1657 elif pp.blob.__class__ == tuple:
1658 cols.append(", ".join(pp.blob))
1660 cols.append(_colourize("OPTIONAL", "red", with_colours))
1662 cols.append(_colourize("DEFAULT", "red", with_colours))
1663 if with_decode_path:
1664 cols.append(_colourize(
1665 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1669 return " ".join(cols)
1672 def pp_console_blob(pp, decode_path_len_decrease=0):
1673 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1674 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1675 if decode_path_len > 0:
1676 cols.append(" ." * (decode_path_len + 1))
1677 if pp.blob.__class__ == binary_type:
1678 blob = hexenc(pp.blob).upper()
1679 for i in six_xrange(0, len(blob), 32):
1680 chunk = blob[i:i + 32]
1681 yield " ".join(cols + [colonize_hex(chunk)])
1682 elif pp.blob.__class__ == tuple:
1683 yield " ".join(cols + [", ".join(pp.blob)])
1691 with_decode_path=False,
1692 decode_path_only=(),
1694 """Pretty print object
1696 :param Obj obj: object you want to pretty print
1697 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1698 Its human readable form is printed when OID is met
1699 :param big_blobs: if large binary objects are met (like OctetString
1700 values), do we need to print them too, on separate
1702 :param with_colours: colourize output, if ``termcolor`` library
1704 :param with_decode_path: print decode path
1705 :param decode_path_only: print only that specified decode path
1707 def _pprint_pps(pps):
1709 if hasattr(pp, "_fields"):
1711 decode_path_only != () and
1713 str(p) for p in pp.decode_path[:len(decode_path_only)]
1714 ) != decode_path_only
1718 yield pp_console_row(
1723 with_colours=with_colours,
1724 with_decode_path=with_decode_path,
1725 decode_path_len_decrease=len(decode_path_only),
1727 for row in pp_console_blob(
1729 decode_path_len_decrease=len(decode_path_only),
1733 yield pp_console_row(
1738 with_colours=with_colours,
1739 with_decode_path=with_decode_path,
1740 decode_path_len_decrease=len(decode_path_only),
1743 for row in _pprint_pps(pp):
1745 return "\n".join(_pprint_pps(obj.pps()))
1748 ########################################################################
1749 # ASN.1 primitive types
1750 ########################################################################
1752 BooleanState = namedtuple("BooleanState", (
1765 ), **NAMEDTUPLE_KWARGS)
1769 """``BOOLEAN`` boolean type
1771 >>> b = Boolean(True)
1773 >>> b == Boolean(True)
1779 tag_default = tag_encode(1)
1780 asn1_type_name = "BOOLEAN"
1792 :param value: set the value. Either boolean type, or
1793 :py:class:`pyderasn.Boolean` object
1794 :param bytes impl: override default tag with ``IMPLICIT`` one
1795 :param bytes expl: override default tag with ``EXPLICIT`` one
1796 :param default: set default value. Type same as in ``value``
1797 :param bool optional: is object ``OPTIONAL`` in sequence
1799 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1800 self._value = None if value is None else self._value_sanitize(value)
1801 if default is not None:
1802 default = self._value_sanitize(default)
1803 self.default = self.__class__(
1809 self._value = default
1811 def _value_sanitize(self, value):
1812 if value.__class__ == bool:
1814 if issubclass(value.__class__, Boolean):
1816 raise InvalidValueType((self.__class__, bool))
1820 return self._value is not None
1822 def __getstate__(self):
1823 return BooleanState(
1838 def __setstate__(self, state):
1839 super(Boolean, self).__setstate__(state)
1840 self._value = state.value
1841 self.tag = state.tag
1842 self._expl = state.expl
1843 self.default = state.default
1844 self.optional = state.optional
1845 self.offset = state.offset
1846 self.llen = state.llen
1847 self.vlen = state.vlen
1848 self.expl_lenindef = state.expl_lenindef
1849 self.lenindef = state.lenindef
1850 self.ber_encoded = state.ber_encoded
1852 def __nonzero__(self):
1853 self._assert_ready()
1857 self._assert_ready()
1860 def __eq__(self, their):
1861 if their.__class__ == bool:
1862 return self._value == their
1863 if not issubclass(their.__class__, Boolean):
1866 self._value == their._value and
1867 self.tag == their.tag and
1868 self._expl == their._expl
1879 return self.__class__(
1881 impl=self.tag if impl is None else impl,
1882 expl=self._expl if expl is None else expl,
1883 default=self.default if default is None else default,
1884 optional=self.optional if optional is None else optional,
1888 self._assert_ready()
1892 (b"\xFF" if self._value else b"\x00"),
1895 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1897 t, _, lv = tag_strip(tlv)
1898 except DecodeError as err:
1899 raise err.__class__(
1901 klass=self.__class__,
1902 decode_path=decode_path,
1907 klass=self.__class__,
1908 decode_path=decode_path,
1914 l, _, v = len_decode(lv)
1915 except DecodeError as err:
1916 raise err.__class__(
1918 klass=self.__class__,
1919 decode_path=decode_path,
1923 raise InvalidLength(
1924 "Boolean's length must be equal to 1",
1925 klass=self.__class__,
1926 decode_path=decode_path,
1930 raise NotEnoughData(
1931 "encoded length is longer than data",
1932 klass=self.__class__,
1933 decode_path=decode_path,
1936 first_octet = byte2int(v)
1938 if first_octet == 0:
1940 elif first_octet == 0xFF:
1942 elif ctx.get("bered", False):
1947 "unacceptable Boolean value",
1948 klass=self.__class__,
1949 decode_path=decode_path,
1952 obj = self.__class__(
1956 default=self.default,
1957 optional=self.optional,
1958 _decoded=(offset, 1, 1),
1960 obj.ber_encoded = ber_encoded
1964 return pp_console_row(next(self.pps()))
1966 def pps(self, decode_path=()):
1969 asn1_type_name=self.asn1_type_name,
1970 obj_name=self.__class__.__name__,
1971 decode_path=decode_path,
1972 value=str(self._value) if self.ready else None,
1973 optional=self.optional,
1974 default=self == self.default,
1975 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1976 expl=None if self._expl is None else tag_decode(self._expl),
1981 expl_offset=self.expl_offset if self.expled else None,
1982 expl_tlen=self.expl_tlen if self.expled else None,
1983 expl_llen=self.expl_llen if self.expled else None,
1984 expl_vlen=self.expl_vlen if self.expled else None,
1985 expl_lenindef=self.expl_lenindef,
1986 ber_encoded=self.ber_encoded,
1989 for pp in self.pps_lenindef(decode_path):
1993 IntegerState = namedtuple("IntegerState", (
2009 ), **NAMEDTUPLE_KWARGS)
2013 """``INTEGER`` integer type
2015 >>> b = Integer(-123)
2017 >>> b == Integer(-123)
2022 >>> Integer(2, bounds=(1, 3))
2024 >>> Integer(5, bounds=(1, 3))
2025 Traceback (most recent call last):
2026 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2030 class Version(Integer):
2037 >>> v = Version("v1")
2044 {'v3': 2, 'v1': 0, 'v2': 1}
2046 __slots__ = ("specs", "_bound_min", "_bound_max")
2047 tag_default = tag_encode(2)
2048 asn1_type_name = "INTEGER"
2062 :param value: set the value. Either integer type, named value
2063 (if ``schema`` is specified in the class), or
2064 :py:class:`pyderasn.Integer` object
2065 :param bounds: set ``(MIN, MAX)`` value constraint.
2066 (-inf, +inf) by default
2067 :param bytes impl: override default tag with ``IMPLICIT`` one
2068 :param bytes expl: override default tag with ``EXPLICIT`` one
2069 :param default: set default value. Type same as in ``value``
2070 :param bool optional: is object ``OPTIONAL`` in sequence
2072 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2074 specs = getattr(self, "schema", {}) if _specs is None else _specs
2075 self.specs = specs if specs.__class__ == dict else dict(specs)
2076 self._bound_min, self._bound_max = getattr(
2079 (float("-inf"), float("+inf")),
2080 ) if bounds is None else bounds
2081 if value is not None:
2082 self._value = self._value_sanitize(value)
2083 if default is not None:
2084 default = self._value_sanitize(default)
2085 self.default = self.__class__(
2091 if self._value is None:
2092 self._value = default
2094 def _value_sanitize(self, value):
2095 if isinstance(value, integer_types):
2097 elif issubclass(value.__class__, Integer):
2098 value = value._value
2099 elif value.__class__ == str:
2100 value = self.specs.get(value)
2102 raise ObjUnknown("integer value: %s" % value)
2104 raise InvalidValueType((self.__class__, int, str))
2105 if not self._bound_min <= value <= self._bound_max:
2106 raise BoundsError(self._bound_min, value, self._bound_max)
2111 return self._value is not None
2113 def __getstate__(self):
2114 return IntegerState(
2132 def __setstate__(self, state):
2133 super(Integer, self).__setstate__(state)
2134 self.specs = state.specs
2135 self._value = state.value
2136 self._bound_min = state.bound_min
2137 self._bound_max = state.bound_max
2138 self.tag = state.tag
2139 self._expl = state.expl
2140 self.default = state.default
2141 self.optional = state.optional
2142 self.offset = state.offset
2143 self.llen = state.llen
2144 self.vlen = state.vlen
2145 self.expl_lenindef = state.expl_lenindef
2146 self.lenindef = state.lenindef
2147 self.ber_encoded = state.ber_encoded
2150 self._assert_ready()
2151 return int(self._value)
2154 self._assert_ready()
2157 bytes(self._expl or b"") +
2158 str(self._value).encode("ascii"),
2161 def __eq__(self, their):
2162 if isinstance(their, integer_types):
2163 return self._value == their
2164 if not issubclass(their.__class__, Integer):
2167 self._value == their._value and
2168 self.tag == their.tag and
2169 self._expl == their._expl
2172 def __lt__(self, their):
2173 return self._value < their._value
2177 for name, value in iteritems(self.specs):
2178 if value == self._value:
2191 return self.__class__(
2194 (self._bound_min, self._bound_max)
2195 if bounds is None else bounds
2197 impl=self.tag if impl is None else impl,
2198 expl=self._expl if expl is None else expl,
2199 default=self.default if default is None else default,
2200 optional=self.optional if optional is None else optional,
2205 self._assert_ready()
2209 octets = bytearray([0])
2213 octets = bytearray()
2215 octets.append((value & 0xFF) ^ 0xFF)
2217 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2220 octets = bytearray()
2222 octets.append(value & 0xFF)
2224 if octets[-1] & 0x80 > 0:
2227 octets = bytes(octets)
2229 bytes_len = ceil(value.bit_length() / 8) or 1
2232 octets = value.to_bytes(
2237 except OverflowError:
2241 return b"".join((self.tag, len_encode(len(octets)), octets))
2243 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2245 t, _, lv = tag_strip(tlv)
2246 except DecodeError as err:
2247 raise err.__class__(
2249 klass=self.__class__,
2250 decode_path=decode_path,
2255 klass=self.__class__,
2256 decode_path=decode_path,
2262 l, llen, v = len_decode(lv)
2263 except DecodeError as err:
2264 raise err.__class__(
2266 klass=self.__class__,
2267 decode_path=decode_path,
2271 raise NotEnoughData(
2272 "encoded length is longer than data",
2273 klass=self.__class__,
2274 decode_path=decode_path,
2278 raise NotEnoughData(
2280 klass=self.__class__,
2281 decode_path=decode_path,
2284 v, tail = v[:l], v[l:]
2285 first_octet = byte2int(v)
2287 second_octet = byte2int(v[1:])
2289 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2290 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2293 "non normalized integer",
2294 klass=self.__class__,
2295 decode_path=decode_path,
2300 if first_octet & 0x80 > 0:
2301 octets = bytearray()
2302 for octet in bytearray(v):
2303 octets.append(octet ^ 0xFF)
2304 for octet in octets:
2305 value = (value << 8) | octet
2309 for octet in bytearray(v):
2310 value = (value << 8) | octet
2312 value = int.from_bytes(v, byteorder="big", signed=True)
2314 obj = self.__class__(
2316 bounds=(self._bound_min, self._bound_max),
2319 default=self.default,
2320 optional=self.optional,
2322 _decoded=(offset, llen, l),
2324 except BoundsError as err:
2327 klass=self.__class__,
2328 decode_path=decode_path,
2334 return pp_console_row(next(self.pps()))
2336 def pps(self, decode_path=()):
2339 asn1_type_name=self.asn1_type_name,
2340 obj_name=self.__class__.__name__,
2341 decode_path=decode_path,
2342 value=(self.named or str(self._value)) if self.ready else None,
2343 optional=self.optional,
2344 default=self == self.default,
2345 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2346 expl=None if self._expl is None else tag_decode(self._expl),
2351 expl_offset=self.expl_offset if self.expled else None,
2352 expl_tlen=self.expl_tlen if self.expled else None,
2353 expl_llen=self.expl_llen if self.expled else None,
2354 expl_vlen=self.expl_vlen if self.expled else None,
2355 expl_lenindef=self.expl_lenindef,
2358 for pp in self.pps_lenindef(decode_path):
2362 BitStringState = namedtuple("BitStringState", (
2378 ), **NAMEDTUPLE_KWARGS)
2381 class BitString(Obj):
2382 """``BIT STRING`` bit string type
2384 >>> BitString(b"hello world")
2385 BIT STRING 88 bits 68656c6c6f20776f726c64
2388 >>> b == b"hello world"
2393 >>> BitString("'0A3B5F291CD'H")
2394 BIT STRING 44 bits 0a3b5f291cd0
2395 >>> b = BitString("'010110000000'B")
2396 BIT STRING 12 bits 5800
2399 >>> b[0], b[1], b[2], b[3]
2400 (False, True, False, True)
2404 [False, True, False, True, True, False, False, False, False, False, False, False]
2408 class KeyUsage(BitString):
2410 ("digitalSignature", 0),
2411 ("nonRepudiation", 1),
2412 ("keyEncipherment", 2),
2415 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2416 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2418 ['nonRepudiation', 'keyEncipherment']
2420 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2424 Pay attention that BIT STRING can be encoded both in primitive
2425 and constructed forms. Decoder always checks constructed form tag
2426 additionally to specified primitive one. If BER decoding is
2427 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2428 of DER restrictions.
2430 __slots__ = ("tag_constructed", "specs", "defined")
2431 tag_default = tag_encode(3)
2432 asn1_type_name = "BIT STRING"
2445 :param value: set the value. Either binary type, tuple of named
2446 values (if ``schema`` is specified in the class),
2447 string in ``'XXX...'B`` form, or
2448 :py:class:`pyderasn.BitString` object
2449 :param bytes impl: override default tag with ``IMPLICIT`` one
2450 :param bytes expl: override default tag with ``EXPLICIT`` one
2451 :param default: set default value. Type same as in ``value``
2452 :param bool optional: is object ``OPTIONAL`` in sequence
2454 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2455 specs = getattr(self, "schema", {}) if _specs is None else _specs
2456 self.specs = specs if specs.__class__ == dict else dict(specs)
2457 self._value = None if value is None else self._value_sanitize(value)
2458 if default is not None:
2459 default = self._value_sanitize(default)
2460 self.default = self.__class__(
2466 self._value = default
2468 tag_klass, _, tag_num = tag_decode(self.tag)
2469 self.tag_constructed = tag_encode(
2471 form=TagFormConstructed,
2475 def _bits2octets(self, bits):
2476 if len(self.specs) > 0:
2477 bits = bits.rstrip("0")
2479 bits += "0" * ((8 - (bit_len % 8)) % 8)
2480 octets = bytearray(len(bits) // 8)
2481 for i in six_xrange(len(octets)):
2482 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2483 return bit_len, bytes(octets)
2485 def _value_sanitize(self, value):
2486 if isinstance(value, (string_types, binary_type)):
2488 isinstance(value, string_types) and
2489 value.startswith("'")
2491 if value.endswith("'B"):
2493 if not frozenset(value) <= SET01:
2494 raise ValueError("B's coding contains unacceptable chars")
2495 return self._bits2octets(value)
2496 if value.endswith("'H"):
2500 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2502 if value.__class__ == binary_type:
2503 return (len(value) * 8, value)
2504 raise InvalidValueType((self.__class__, string_types, binary_type))
2505 if value.__class__ == tuple:
2508 isinstance(value[0], integer_types) and
2509 value[1].__class__ == binary_type
2514 bit = self.specs.get(name)
2516 raise ObjUnknown("BitString value: %s" % name)
2519 return self._bits2octets("")
2520 bits = frozenset(bits)
2521 return self._bits2octets("".join(
2522 ("1" if bit in bits else "0")
2523 for bit in six_xrange(max(bits) + 1)
2525 if issubclass(value.__class__, BitString):
2527 raise InvalidValueType((self.__class__, binary_type, string_types))
2531 return self._value is not None
2533 def __getstate__(self):
2534 return BitStringState(
2548 self.tag_constructed,
2552 def __setstate__(self, state):
2553 super(BitString, self).__setstate__(state)
2554 self.specs = state.specs
2555 self._value = state.value
2556 self.tag = state.tag
2557 self._expl = state.expl
2558 self.default = state.default
2559 self.optional = state.optional
2560 self.offset = state.offset
2561 self.llen = state.llen
2562 self.vlen = state.vlen
2563 self.expl_lenindef = state.expl_lenindef
2564 self.lenindef = state.lenindef
2565 self.ber_encoded = state.ber_encoded
2566 self.tag_constructed = state.tag_constructed
2567 self.defined = state.defined
2570 self._assert_ready()
2571 for i in six_xrange(self._value[0]):
2576 self._assert_ready()
2577 return self._value[0]
2579 def __bytes__(self):
2580 self._assert_ready()
2581 return self._value[1]
2583 def __eq__(self, their):
2584 if their.__class__ == bytes:
2585 return self._value[1] == their
2586 if not issubclass(their.__class__, BitString):
2589 self._value == their._value and
2590 self.tag == their.tag and
2591 self._expl == their._expl
2596 return [name for name, bit in iteritems(self.specs) if self[bit]]
2606 return self.__class__(
2608 impl=self.tag if impl is None else impl,
2609 expl=self._expl if expl is None else expl,
2610 default=self.default if default is None else default,
2611 optional=self.optional if optional is None else optional,
2615 def __getitem__(self, key):
2616 if key.__class__ == int:
2617 bit_len, octets = self._value
2621 byte2int(memoryview(octets)[key // 8:]) >>
2624 if isinstance(key, string_types):
2625 value = self.specs.get(key)
2627 raise ObjUnknown("BitString value: %s" % key)
2629 raise InvalidValueType((int, str))
2632 self._assert_ready()
2633 bit_len, octets = self._value
2636 len_encode(len(octets) + 1),
2637 int2byte((8 - bit_len % 8) % 8),
2641 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2643 t, tlen, lv = tag_strip(tlv)
2644 except DecodeError as err:
2645 raise err.__class__(
2647 klass=self.__class__,
2648 decode_path=decode_path,
2652 if tag_only: # pragma: no cover
2655 l, llen, v = len_decode(lv)
2656 except DecodeError as err:
2657 raise err.__class__(
2659 klass=self.__class__,
2660 decode_path=decode_path,
2664 raise NotEnoughData(
2665 "encoded length is longer than data",
2666 klass=self.__class__,
2667 decode_path=decode_path,
2671 raise NotEnoughData(
2673 klass=self.__class__,
2674 decode_path=decode_path,
2677 pad_size = byte2int(v)
2678 if l == 1 and pad_size != 0:
2680 "invalid empty value",
2681 klass=self.__class__,
2682 decode_path=decode_path,
2688 klass=self.__class__,
2689 decode_path=decode_path,
2692 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2695 klass=self.__class__,
2696 decode_path=decode_path,
2699 v, tail = v[:l], v[l:]
2700 obj = self.__class__(
2701 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2704 default=self.default,
2705 optional=self.optional,
2707 _decoded=(offset, llen, l),
2710 if t != self.tag_constructed:
2712 klass=self.__class__,
2713 decode_path=decode_path,
2716 if not ctx.get("bered", False):
2718 "unallowed BER constructed encoding",
2719 klass=self.__class__,
2720 decode_path=decode_path,
2723 if tag_only: # pragma: no cover
2727 l, llen, v = len_decode(lv)
2728 except LenIndefForm:
2729 llen, l, v = 1, 0, lv[1:]
2731 except DecodeError as err:
2732 raise err.__class__(
2734 klass=self.__class__,
2735 decode_path=decode_path,
2739 raise NotEnoughData(
2740 "encoded length is longer than data",
2741 klass=self.__class__,
2742 decode_path=decode_path,
2745 if not lenindef and l == 0:
2746 raise NotEnoughData(
2748 klass=self.__class__,
2749 decode_path=decode_path,
2753 sub_offset = offset + tlen + llen
2757 if v[:EOC_LEN].tobytes() == EOC:
2764 "chunk out of bounds",
2765 klass=self.__class__,
2766 decode_path=decode_path + (str(len(chunks) - 1),),
2767 offset=chunks[-1].offset,
2769 sub_decode_path = decode_path + (str(len(chunks)),)
2771 chunk, v_tail = BitString().decode(
2774 decode_path=sub_decode_path,
2777 _ctx_immutable=False,
2781 "expected BitString encoded chunk",
2782 klass=self.__class__,
2783 decode_path=sub_decode_path,
2786 chunks.append(chunk)
2787 sub_offset += chunk.tlvlen
2788 vlen += chunk.tlvlen
2790 if len(chunks) == 0:
2793 klass=self.__class__,
2794 decode_path=decode_path,
2799 for chunk_i, chunk in enumerate(chunks[:-1]):
2800 if chunk.bit_len % 8 != 0:
2802 "BitString chunk is not multiple of 8 bits",
2803 klass=self.__class__,
2804 decode_path=decode_path + (str(chunk_i),),
2805 offset=chunk.offset,
2807 values.append(bytes(chunk))
2808 bit_len += chunk.bit_len
2809 chunk_last = chunks[-1]
2810 values.append(bytes(chunk_last))
2811 bit_len += chunk_last.bit_len
2812 obj = self.__class__(
2813 value=(bit_len, b"".join(values)),
2816 default=self.default,
2817 optional=self.optional,
2819 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2821 obj.lenindef = lenindef
2822 obj.ber_encoded = True
2823 return obj, (v[EOC_LEN:] if lenindef else v)
2826 return pp_console_row(next(self.pps()))
2828 def pps(self, decode_path=()):
2832 bit_len, blob = self._value
2833 value = "%d bits" % bit_len
2834 if len(self.specs) > 0:
2835 blob = tuple(self.named)
2838 asn1_type_name=self.asn1_type_name,
2839 obj_name=self.__class__.__name__,
2840 decode_path=decode_path,
2843 optional=self.optional,
2844 default=self == self.default,
2845 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2846 expl=None if self._expl is None else tag_decode(self._expl),
2851 expl_offset=self.expl_offset if self.expled else None,
2852 expl_tlen=self.expl_tlen if self.expled else None,
2853 expl_llen=self.expl_llen if self.expled else None,
2854 expl_vlen=self.expl_vlen if self.expled else None,
2855 expl_lenindef=self.expl_lenindef,
2856 lenindef=self.lenindef,
2857 ber_encoded=self.ber_encoded,
2860 defined_by, defined = self.defined or (None, None)
2861 if defined_by is not None:
2863 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2865 for pp in self.pps_lenindef(decode_path):
2869 OctetStringState = namedtuple("OctetStringState", (
2886 ), **NAMEDTUPLE_KWARGS)
2889 class OctetString(Obj):
2890 """``OCTET STRING`` binary string type
2892 >>> s = OctetString(b"hello world")
2893 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2894 >>> s == OctetString(b"hello world")
2899 >>> OctetString(b"hello", bounds=(4, 4))
2900 Traceback (most recent call last):
2901 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2902 >>> OctetString(b"hell", bounds=(4, 4))
2903 OCTET STRING 4 bytes 68656c6c
2907 Pay attention that OCTET STRING can be encoded both in primitive
2908 and constructed forms. Decoder always checks constructed form tag
2909 additionally to specified primitive one. If BER decoding is
2910 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2911 of DER restrictions.
2913 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2914 tag_default = tag_encode(4)
2915 asn1_type_name = "OCTET STRING"
2929 :param value: set the value. Either binary type, or
2930 :py:class:`pyderasn.OctetString` object
2931 :param bounds: set ``(MIN, MAX)`` value size constraint.
2932 (-inf, +inf) by default
2933 :param bytes impl: override default tag with ``IMPLICIT`` one
2934 :param bytes expl: override default tag with ``EXPLICIT`` one
2935 :param default: set default value. Type same as in ``value``
2936 :param bool optional: is object ``OPTIONAL`` in sequence
2938 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2940 self._bound_min, self._bound_max = getattr(
2944 ) if bounds is None else bounds
2945 if value is not None:
2946 self._value = self._value_sanitize(value)
2947 if default is not None:
2948 default = self._value_sanitize(default)
2949 self.default = self.__class__(
2954 if self._value is None:
2955 self._value = default
2957 tag_klass, _, tag_num = tag_decode(self.tag)
2958 self.tag_constructed = tag_encode(
2960 form=TagFormConstructed,
2964 def _value_sanitize(self, value):
2965 if value.__class__ == binary_type:
2967 elif issubclass(value.__class__, OctetString):
2968 value = value._value
2970 raise InvalidValueType((self.__class__, bytes))
2971 if not self._bound_min <= len(value) <= self._bound_max:
2972 raise BoundsError(self._bound_min, len(value), self._bound_max)
2977 return self._value is not None
2979 def __getstate__(self):
2980 return OctetStringState(
2995 self.tag_constructed,
2999 def __setstate__(self, state):
3000 super(OctetString, self).__setstate__(state)
3001 self._value = state.value
3002 self._bound_min = state.bound_min
3003 self._bound_max = state.bound_max
3004 self.tag = state.tag
3005 self._expl = state.expl
3006 self.default = state.default
3007 self.optional = state.optional
3008 self.offset = state.offset
3009 self.llen = state.llen
3010 self.vlen = state.vlen
3011 self.expl_lenindef = state.expl_lenindef
3012 self.lenindef = state.lenindef
3013 self.ber_encoded = state.ber_encoded
3014 self.tag_constructed = state.tag_constructed
3015 self.defined = state.defined
3017 def __bytes__(self):
3018 self._assert_ready()
3021 def __eq__(self, their):
3022 if their.__class__ == binary_type:
3023 return self._value == their
3024 if not issubclass(their.__class__, OctetString):
3027 self._value == their._value and
3028 self.tag == their.tag and
3029 self._expl == their._expl
3032 def __lt__(self, their):
3033 return self._value < their._value
3044 return self.__class__(
3047 (self._bound_min, self._bound_max)
3048 if bounds is None else bounds
3050 impl=self.tag if impl is None else impl,
3051 expl=self._expl if expl is None else expl,
3052 default=self.default if default is None else default,
3053 optional=self.optional if optional is None else optional,
3057 self._assert_ready()
3060 len_encode(len(self._value)),
3064 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3066 t, tlen, lv = tag_strip(tlv)
3067 except DecodeError as err:
3068 raise err.__class__(
3070 klass=self.__class__,
3071 decode_path=decode_path,
3078 l, llen, v = len_decode(lv)
3079 except DecodeError as err:
3080 raise err.__class__(
3082 klass=self.__class__,
3083 decode_path=decode_path,
3087 raise NotEnoughData(
3088 "encoded length is longer than data",
3089 klass=self.__class__,
3090 decode_path=decode_path,
3093 v, tail = v[:l], v[l:]
3095 obj = self.__class__(
3097 bounds=(self._bound_min, self._bound_max),
3100 default=self.default,
3101 optional=self.optional,
3102 _decoded=(offset, llen, l),
3105 except DecodeError as err:
3108 klass=self.__class__,
3109 decode_path=decode_path,
3112 except BoundsError as err:
3115 klass=self.__class__,
3116 decode_path=decode_path,
3120 if t != self.tag_constructed:
3122 klass=self.__class__,
3123 decode_path=decode_path,
3126 if not ctx.get("bered", False):
3128 "unallowed BER constructed encoding",
3129 klass=self.__class__,
3130 decode_path=decode_path,
3137 l, llen, v = len_decode(lv)
3138 except LenIndefForm:
3139 llen, l, v = 1, 0, lv[1:]
3141 except DecodeError as err:
3142 raise err.__class__(
3144 klass=self.__class__,
3145 decode_path=decode_path,
3149 raise NotEnoughData(
3150 "encoded length is longer than data",
3151 klass=self.__class__,
3152 decode_path=decode_path,
3156 sub_offset = offset + tlen + llen
3160 if v[:EOC_LEN].tobytes() == EOC:
3167 "chunk out of bounds",
3168 klass=self.__class__,
3169 decode_path=decode_path + (str(len(chunks) - 1),),
3170 offset=chunks[-1].offset,
3172 sub_decode_path = decode_path + (str(len(chunks)),)
3174 chunk, v_tail = OctetString().decode(
3177 decode_path=sub_decode_path,
3180 _ctx_immutable=False,
3184 "expected OctetString encoded chunk",
3185 klass=self.__class__,
3186 decode_path=sub_decode_path,
3189 chunks.append(chunk)
3190 sub_offset += chunk.tlvlen
3191 vlen += chunk.tlvlen
3194 obj = self.__class__(
3195 value=b"".join(bytes(chunk) for chunk in chunks),
3196 bounds=(self._bound_min, self._bound_max),
3199 default=self.default,
3200 optional=self.optional,
3201 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3204 except DecodeError as err:
3207 klass=self.__class__,
3208 decode_path=decode_path,
3211 except BoundsError as err:
3214 klass=self.__class__,
3215 decode_path=decode_path,
3218 obj.lenindef = lenindef
3219 obj.ber_encoded = True
3220 return obj, (v[EOC_LEN:] if lenindef else v)
3223 return pp_console_row(next(self.pps()))
3225 def pps(self, decode_path=()):
3228 asn1_type_name=self.asn1_type_name,
3229 obj_name=self.__class__.__name__,
3230 decode_path=decode_path,
3231 value=("%d bytes" % len(self._value)) if self.ready else None,
3232 blob=self._value if self.ready else None,
3233 optional=self.optional,
3234 default=self == self.default,
3235 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3236 expl=None if self._expl is None else tag_decode(self._expl),
3241 expl_offset=self.expl_offset if self.expled else None,
3242 expl_tlen=self.expl_tlen if self.expled else None,
3243 expl_llen=self.expl_llen if self.expled else None,
3244 expl_vlen=self.expl_vlen if self.expled else None,
3245 expl_lenindef=self.expl_lenindef,
3246 lenindef=self.lenindef,
3247 ber_encoded=self.ber_encoded,
3250 defined_by, defined = self.defined or (None, None)
3251 if defined_by is not None:
3253 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3255 for pp in self.pps_lenindef(decode_path):
3259 NullState = namedtuple("NullState", (
3271 ), **NAMEDTUPLE_KWARGS)
3275 """``NULL`` null object
3283 tag_default = tag_encode(5)
3284 asn1_type_name = "NULL"
3288 value=None, # unused, but Sequence passes it
3295 :param bytes impl: override default tag with ``IMPLICIT`` one
3296 :param bytes expl: override default tag with ``EXPLICIT`` one
3297 :param bool optional: is object ``OPTIONAL`` in sequence
3299 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3306 def __getstate__(self):
3321 def __setstate__(self, state):
3322 super(Null, self).__setstate__(state)
3323 self.tag = state.tag
3324 self._expl = state.expl
3325 self.default = state.default
3326 self.optional = state.optional
3327 self.offset = state.offset
3328 self.llen = state.llen
3329 self.vlen = state.vlen
3330 self.expl_lenindef = state.expl_lenindef
3331 self.lenindef = state.lenindef
3332 self.ber_encoded = state.ber_encoded
3334 def __eq__(self, their):
3335 if not issubclass(their.__class__, Null):
3338 self.tag == their.tag and
3339 self._expl == their._expl
3349 return self.__class__(
3350 impl=self.tag if impl is None else impl,
3351 expl=self._expl if expl is None else expl,
3352 optional=self.optional if optional is None else optional,
3356 return self.tag + len_encode(0)
3358 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3360 t, _, lv = tag_strip(tlv)
3361 except DecodeError as err:
3362 raise err.__class__(
3364 klass=self.__class__,
3365 decode_path=decode_path,
3370 klass=self.__class__,
3371 decode_path=decode_path,
3374 if tag_only: # pragma: no cover
3377 l, _, v = len_decode(lv)
3378 except DecodeError as err:
3379 raise err.__class__(
3381 klass=self.__class__,
3382 decode_path=decode_path,
3386 raise InvalidLength(
3387 "Null must have zero length",
3388 klass=self.__class__,
3389 decode_path=decode_path,
3392 obj = self.__class__(
3395 optional=self.optional,
3396 _decoded=(offset, 1, 0),
3401 return pp_console_row(next(self.pps()))
3403 def pps(self, decode_path=()):
3406 asn1_type_name=self.asn1_type_name,
3407 obj_name=self.__class__.__name__,
3408 decode_path=decode_path,
3409 optional=self.optional,
3410 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3411 expl=None if self._expl is None else tag_decode(self._expl),
3416 expl_offset=self.expl_offset if self.expled else None,
3417 expl_tlen=self.expl_tlen if self.expled else None,
3418 expl_llen=self.expl_llen if self.expled else None,
3419 expl_vlen=self.expl_vlen if self.expled else None,
3420 expl_lenindef=self.expl_lenindef,
3423 for pp in self.pps_lenindef(decode_path):
3427 ObjectIdentifierState = namedtuple("ObjectIdentifierState", (
3441 ), **NAMEDTUPLE_KWARGS)
3444 class ObjectIdentifier(Obj):
3445 """``OBJECT IDENTIFIER`` OID type
3447 >>> oid = ObjectIdentifier((1, 2, 3))
3448 OBJECT IDENTIFIER 1.2.3
3449 >>> oid == ObjectIdentifier("1.2.3")
3455 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3456 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3458 >>> str(ObjectIdentifier((3, 1)))
3459 Traceback (most recent call last):
3460 pyderasn.InvalidOID: unacceptable first arc value
3462 __slots__ = ("defines",)
3463 tag_default = tag_encode(6)
3464 asn1_type_name = "OBJECT IDENTIFIER"
3477 :param value: set the value. Either tuples of integers,
3478 string of "."-concatenated integers, or
3479 :py:class:`pyderasn.ObjectIdentifier` object
3480 :param defines: sequence of tuples. Each tuple has two elements.
3481 First one is relative to current one decode
3482 path, aiming to the field defined by that OID.
3483 Read about relative path in
3484 :py:func:`pyderasn.abs_decode_path`. Second
3485 tuple element is ``{OID: pyderasn.Obj()}``
3486 dictionary, mapping between current OID value
3487 and structure applied to defined field.
3488 :ref:`Read about DEFINED BY <definedby>`
3489 :param bytes impl: override default tag with ``IMPLICIT`` one
3490 :param bytes expl: override default tag with ``EXPLICIT`` one
3491 :param default: set default value. Type same as in ``value``
3492 :param bool optional: is object ``OPTIONAL`` in sequence
3494 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3496 if value is not None:
3497 self._value = self._value_sanitize(value)
3498 if default is not None:
3499 default = self._value_sanitize(default)
3500 self.default = self.__class__(
3505 if self._value is None:
3506 self._value = default
3507 self.defines = defines
3509 def __add__(self, their):
3510 if their.__class__ == tuple:
3511 return self.__class__(self._value + their)
3512 if isinstance(their, self.__class__):
3513 return self.__class__(self._value + their._value)
3514 raise InvalidValueType((self.__class__, tuple))
3516 def _value_sanitize(self, value):
3517 if issubclass(value.__class__, ObjectIdentifier):
3519 if isinstance(value, string_types):
3521 value = tuple(pureint(arc) for arc in value.split("."))
3523 raise InvalidOID("unacceptable arcs values")
3524 if value.__class__ == tuple:
3526 raise InvalidOID("less than 2 arcs")
3527 first_arc = value[0]
3528 if first_arc in (0, 1):
3529 if not (0 <= value[1] <= 39):
3530 raise InvalidOID("second arc is too wide")
3531 elif first_arc == 2:
3534 raise InvalidOID("unacceptable first arc value")
3535 if not all(arc >= 0 for arc in value):
3536 raise InvalidOID("negative arc value")
3538 raise InvalidValueType((self.__class__, str, tuple))
3542 return self._value is not None
3544 def __getstate__(self):
3545 return ObjectIdentifierState(
3561 def __setstate__(self, state):
3562 super(ObjectIdentifier, self).__setstate__(state)
3563 self._value = state.value
3564 self.tag = state.tag
3565 self._expl = state.expl
3566 self.default = state.default
3567 self.optional = state.optional
3568 self.offset = state.offset
3569 self.llen = state.llen
3570 self.vlen = state.vlen
3571 self.expl_lenindef = state.expl_lenindef
3572 self.lenindef = state.lenindef
3573 self.ber_encoded = state.ber_encoded
3574 self.defines = state.defines
3577 self._assert_ready()
3578 return iter(self._value)
3581 return ".".join(str(arc) for arc in self._value or ())
3584 self._assert_ready()
3587 bytes(self._expl or b"") +
3588 str(self._value).encode("ascii"),
3591 def __eq__(self, their):
3592 if their.__class__ == tuple:
3593 return self._value == their
3594 if not issubclass(their.__class__, ObjectIdentifier):
3597 self.tag == their.tag and
3598 self._expl == their._expl and
3599 self._value == their._value
3602 def __lt__(self, their):
3603 return self._value < their._value
3614 return self.__class__(
3616 defines=self.defines if defines is None else defines,
3617 impl=self.tag if impl is None else impl,
3618 expl=self._expl if expl is None else expl,
3619 default=self.default if default is None else default,
3620 optional=self.optional if optional is None else optional,
3624 self._assert_ready()
3626 first_value = value[1]
3627 first_arc = value[0]
3630 elif first_arc == 1:
3632 elif first_arc == 2:
3634 else: # pragma: no cover
3635 raise RuntimeError("invalid arc is stored")
3636 octets = [zero_ended_encode(first_value)]
3637 for arc in value[2:]:
3638 octets.append(zero_ended_encode(arc))
3639 v = b"".join(octets)
3640 return b"".join((self.tag, len_encode(len(v)), v))
3642 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3644 t, _, lv = tag_strip(tlv)
3645 except DecodeError as err:
3646 raise err.__class__(
3648 klass=self.__class__,
3649 decode_path=decode_path,
3654 klass=self.__class__,
3655 decode_path=decode_path,
3658 if tag_only: # pragma: no cover
3661 l, llen, v = len_decode(lv)
3662 except DecodeError as err:
3663 raise err.__class__(
3665 klass=self.__class__,
3666 decode_path=decode_path,
3670 raise NotEnoughData(
3671 "encoded length is longer than data",
3672 klass=self.__class__,
3673 decode_path=decode_path,
3677 raise NotEnoughData(
3679 klass=self.__class__,
3680 decode_path=decode_path,
3683 v, tail = v[:l], v[l:]
3690 octet = indexbytes(v, i)
3691 if i == 0 and octet == 0x80:
3692 if ctx.get("bered", False):
3695 raise DecodeError("non normalized arc encoding")
3696 arc = (arc << 7) | (octet & 0x7F)
3697 if octet & 0x80 == 0:
3705 klass=self.__class__,
3706 decode_path=decode_path,
3710 second_arc = arcs[0]
3711 if 0 <= second_arc <= 39:
3713 elif 40 <= second_arc <= 79:
3719 obj = self.__class__(
3720 value=tuple([first_arc, second_arc] + arcs[1:]),
3723 default=self.default,
3724 optional=self.optional,
3725 _decoded=(offset, llen, l),
3728 obj.ber_encoded = True
3732 return pp_console_row(next(self.pps()))
3734 def pps(self, decode_path=()):
3737 asn1_type_name=self.asn1_type_name,
3738 obj_name=self.__class__.__name__,
3739 decode_path=decode_path,
3740 value=str(self) if self.ready else None,
3741 optional=self.optional,
3742 default=self == self.default,
3743 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3744 expl=None if self._expl is None else tag_decode(self._expl),
3749 expl_offset=self.expl_offset if self.expled else None,
3750 expl_tlen=self.expl_tlen if self.expled else None,
3751 expl_llen=self.expl_llen if self.expled else None,
3752 expl_vlen=self.expl_vlen if self.expled else None,
3753 expl_lenindef=self.expl_lenindef,
3754 ber_encoded=self.ber_encoded,
3757 for pp in self.pps_lenindef(decode_path):
3761 class Enumerated(Integer):
3762 """``ENUMERATED`` integer type
3764 This type is identical to :py:class:`pyderasn.Integer`, but requires
3765 schema to be specified and does not accept values missing from it.
3768 tag_default = tag_encode(10)
3769 asn1_type_name = "ENUMERATED"
3780 bounds=None, # dummy argument, workability for Integer.decode
3782 super(Enumerated, self).__init__(
3783 value, bounds, impl, expl, default, optional, _specs, _decoded,
3785 if len(self.specs) == 0:
3786 raise ValueError("schema must be specified")
3788 def _value_sanitize(self, value):
3789 if isinstance(value, self.__class__):
3790 value = value._value
3791 elif isinstance(value, integer_types):
3792 for _value in itervalues(self.specs):
3797 "unknown integer value: %s" % value,
3798 klass=self.__class__,
3800 elif isinstance(value, string_types):
3801 value = self.specs.get(value)
3803 raise ObjUnknown("integer value: %s" % value)
3805 raise InvalidValueType((self.__class__, int, str))
3817 return self.__class__(
3819 impl=self.tag if impl is None else impl,
3820 expl=self._expl if expl is None else expl,
3821 default=self.default if default is None else default,
3822 optional=self.optional if optional is None else optional,
3827 def escape_control_unicode(c):
3828 if unicat(c)[0] == "C":
3829 c = repr(c).lstrip("u").strip("'")
3833 class CommonString(OctetString):
3834 """Common class for all strings
3836 Everything resembles :py:class:`pyderasn.OctetString`, except
3837 ability to deal with unicode text strings.
3839 >>> hexenc("привет мир".encode("utf-8"))
3840 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3841 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3843 >>> s = UTF8String("привет мир")
3844 UTF8String UTF8String привет мир
3846 'привет мир'
3847 >>> hexenc(bytes(s))
3848 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3850 >>> PrintableString("привет мир")
3851 Traceback (most recent call last):
3852 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3854 >>> BMPString("ада", bounds=(2, 2))
3855 Traceback (most recent call last):
3856 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3857 >>> s = BMPString("ад", bounds=(2, 2))
3860 >>> hexenc(bytes(s))
3868 * - :py:class:`pyderasn.UTF8String`
3870 * - :py:class:`pyderasn.NumericString`
3872 * - :py:class:`pyderasn.PrintableString`
3874 * - :py:class:`pyderasn.TeletexString`
3876 * - :py:class:`pyderasn.T61String`
3878 * - :py:class:`pyderasn.VideotexString`
3880 * - :py:class:`pyderasn.IA5String`
3882 * - :py:class:`pyderasn.GraphicString`
3884 * - :py:class:`pyderasn.VisibleString`
3886 * - :py:class:`pyderasn.ISO646String`
3888 * - :py:class:`pyderasn.GeneralString`
3890 * - :py:class:`pyderasn.UniversalString`
3892 * - :py:class:`pyderasn.BMPString`
3897 def _value_sanitize(self, value):
3899 value_decoded = None
3900 if isinstance(value, self.__class__):
3901 value_raw = value._value
3902 elif value.__class__ == text_type:
3903 value_decoded = value
3904 elif value.__class__ == binary_type:
3907 raise InvalidValueType((self.__class__, text_type, binary_type))
3910 value_decoded.encode(self.encoding)
3911 if value_raw is None else value_raw
3914 value_raw.decode(self.encoding)
3915 if value_decoded is None else value_decoded
3917 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3918 raise DecodeError(str(err))
3919 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3927 def __eq__(self, their):
3928 if their.__class__ == binary_type:
3929 return self._value == their
3930 if their.__class__ == text_type:
3931 return self._value == their.encode(self.encoding)
3932 if not isinstance(their, self.__class__):
3935 self._value == their._value and
3936 self.tag == their.tag and
3937 self._expl == their._expl
3940 def __unicode__(self):
3942 return self._value.decode(self.encoding)
3943 return text_type(self._value)
3946 return pp_console_row(next(self.pps(no_unicode=PY2)))
3948 def pps(self, decode_path=(), no_unicode=False):
3952 hexenc(bytes(self)) if no_unicode else
3953 "".join(escape_control_unicode(c) for c in self.__unicode__())
3957 asn1_type_name=self.asn1_type_name,
3958 obj_name=self.__class__.__name__,
3959 decode_path=decode_path,
3961 optional=self.optional,
3962 default=self == self.default,
3963 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3964 expl=None if self._expl is None else tag_decode(self._expl),
3969 expl_offset=self.expl_offset if self.expled else None,
3970 expl_tlen=self.expl_tlen if self.expled else None,
3971 expl_llen=self.expl_llen if self.expled else None,
3972 expl_vlen=self.expl_vlen if self.expled else None,
3973 expl_lenindef=self.expl_lenindef,
3974 ber_encoded=self.ber_encoded,
3977 for pp in self.pps_lenindef(decode_path):
3981 class UTF8String(CommonString):
3983 tag_default = tag_encode(12)
3985 asn1_type_name = "UTF8String"
3988 class AllowableCharsMixin(object):
3990 def allowable_chars(self):
3992 return self._allowable_chars
3993 return frozenset(six_unichr(c) for c in self._allowable_chars)
3996 class NumericString(AllowableCharsMixin, CommonString):
3999 Its value is properly sanitized: only ASCII digits with spaces can
4002 >>> NumericString().allowable_chars
4003 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
4006 tag_default = tag_encode(18)
4008 asn1_type_name = "NumericString"
4009 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
4011 def _value_sanitize(self, value):
4012 value = super(NumericString, self)._value_sanitize(value)
4013 if not frozenset(value) <= self._allowable_chars:
4014 raise DecodeError("non-numeric value")
4018 PrintableStringState = namedtuple(
4019 "PrintableStringState",
4020 OctetStringState._fields + ("allowable_chars",),
4025 class PrintableString(AllowableCharsMixin, CommonString):
4028 Its value is properly sanitized: see X.680 41.4 table 10.
4030 >>> PrintableString().allowable_chars
4031 frozenset([' ', "'", ..., 'z'])
4032 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4033 PrintableString PrintableString foo*bar
4034 >>> obj.allow_asterisk, obj.allow_ampersand
4038 tag_default = tag_encode(19)
4040 asn1_type_name = "PrintableString"
4041 _allowable_chars = frozenset(
4042 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4044 _asterisk = frozenset("*".encode("ascii"))
4045 _ampersand = frozenset("&".encode("ascii"))
4057 allow_asterisk=False,
4058 allow_ampersand=False,
4061 :param allow_asterisk: allow asterisk character
4062 :param allow_ampersand: allow ampersand character
4065 self._allowable_chars |= self._asterisk
4067 self._allowable_chars |= self._ampersand
4068 super(PrintableString, self).__init__(
4069 value, bounds, impl, expl, default, optional, _decoded, ctx,
4073 def allow_asterisk(self):
4074 """Is asterisk character allowed?
4076 return self._asterisk <= self._allowable_chars
4079 def allow_ampersand(self):
4080 """Is ampersand character allowed?
4082 return self._ampersand <= self._allowable_chars
4084 def _value_sanitize(self, value):
4085 value = super(PrintableString, self)._value_sanitize(value)
4086 if not frozenset(value) <= self._allowable_chars:
4087 raise DecodeError("non-printable value")
4090 def __getstate__(self):
4091 return PrintableStringState(
4092 *super(PrintableString, self).__getstate__(),
4093 **{"allowable_chars": self._allowable_chars}
4096 def __setstate__(self, state):
4097 super(PrintableString, self).__setstate__(state)
4098 self._allowable_chars = state.allowable_chars
4109 return self.__class__(
4112 (self._bound_min, self._bound_max)
4113 if bounds is None else bounds
4115 impl=self.tag if impl is None else impl,
4116 expl=self._expl if expl is None else expl,
4117 default=self.default if default is None else default,
4118 optional=self.optional if optional is None else optional,
4119 allow_asterisk=self.allow_asterisk,
4120 allow_ampersand=self.allow_ampersand,
4124 class TeletexString(CommonString):
4126 tag_default = tag_encode(20)
4128 asn1_type_name = "TeletexString"
4131 class T61String(TeletexString):
4133 asn1_type_name = "T61String"
4136 class VideotexString(CommonString):
4138 tag_default = tag_encode(21)
4139 encoding = "iso-8859-1"
4140 asn1_type_name = "VideotexString"
4143 class IA5String(CommonString):
4145 tag_default = tag_encode(22)
4147 asn1_type_name = "IA5"
4150 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4151 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4152 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4155 class VisibleString(CommonString):
4157 tag_default = tag_encode(26)
4159 asn1_type_name = "VisibleString"
4162 UTCTimeState = namedtuple(
4164 OctetStringState._fields + ("ber_raw",),
4169 def str_to_time_fractions(value):
4171 year, v = (v // 10**10), (v % 10**10)
4172 month, v = (v // 10**8), (v % 10**8)
4173 day, v = (v // 10**6), (v % 10**6)
4174 hour, v = (v // 10**4), (v % 10**4)
4175 minute, second = (v // 100), (v % 100)
4176 return year, month, day, hour, minute, second
4179 class UTCTime(VisibleString):
4180 """``UTCTime`` datetime type
4182 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4183 UTCTime UTCTime 2017-09-30T22:07:50
4189 datetime.datetime(2017, 9, 30, 22, 7, 50)
4190 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4191 datetime.datetime(1957, 9, 30, 22, 7, 50)
4193 If BER encoded value was met, then ``ber_raw`` attribute will hold
4194 its raw representation.
4198 Pay attention that UTCTime can not hold full year, so all years
4199 having < 50 years are treated as 20xx, 19xx otherwise, according
4200 to X.509 recommendation.
4204 No strict validation of UTC offsets are made, but very crude:
4206 * minutes are not exceeding 60
4207 * offset value is not exceeding 14 hours
4209 __slots__ = ("ber_raw",)
4210 tag_default = tag_encode(23)
4212 asn1_type_name = "UTCTime"
4222 bounds=None, # dummy argument, workability for OctetString.decode
4226 :param value: set the value. Either datetime type, or
4227 :py:class:`pyderasn.UTCTime` object
4228 :param bytes impl: override default tag with ``IMPLICIT`` one
4229 :param bytes expl: override default tag with ``EXPLICIT`` one
4230 :param default: set default value. Type same as in ``value``
4231 :param bool optional: is object ``OPTIONAL`` in sequence
4233 super(UTCTime, self).__init__(
4234 None, None, impl, expl, None, optional, _decoded, ctx,
4238 if value is not None:
4239 self._value, self.ber_raw = self._value_sanitize(value, ctx)
4240 self.ber_encoded = self.ber_raw is not None
4241 if default is not None:
4242 default, _ = self._value_sanitize(default)
4243 self.default = self.__class__(
4248 if self._value is None:
4249 self._value = default
4251 self.optional = optional
4253 def _strptime_bered(self, value):
4254 year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
4257 raise ValueError("no timezone")
4258 year += 2000 if year < 50 else 1900
4259 decoded = datetime(year, month, day, hour, minute)
4261 if value[-1] == "Z":
4265 raise ValueError("invalid UTC offset")
4266 if value[-5] == "-":
4268 elif value[-5] == "+":
4271 raise ValueError("invalid UTC offset")
4272 v = pureint(value[-4:])
4273 offset, v = (60 * (v % 100)), v // 100
4275 raise ValueError("invalid UTC offset minutes")
4277 if offset > 14 * 3600:
4278 raise ValueError("too big UTC offset")
4282 return offset, decoded
4284 raise ValueError("invalid UTC offset seconds")
4285 seconds = pureint(value)
4287 raise ValueError("invalid seconds value")
4288 return offset, decoded + timedelta(seconds=seconds)
4290 def _strptime(self, value):
4291 # datetime.strptime's format: %y%m%d%H%M%SZ
4292 if len(value) != LEN_YYMMDDHHMMSSZ:
4293 raise ValueError("invalid UTCTime length")
4294 if value[-1] != "Z":
4295 raise ValueError("non UTC timezone")
4296 year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
4297 year += 2000 if year < 50 else 1900
4298 return datetime(year, month, day, hour, minute, second)
4300 def _dt_sanitize(self, value):
4301 if value.year < 1950 or value.year > 2049:
4302 raise ValueError("UTCTime can hold only 1950-2049 years")
4303 return value.replace(microsecond=0)
4305 def _value_sanitize(self, value, ctx=None):
4306 if value.__class__ == binary_type:
4308 value_decoded = value.decode("ascii")
4309 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4310 raise DecodeError("invalid UTCTime encoding: %r" % err)
4313 return self._strptime(value_decoded), None
4314 except (TypeError, ValueError) as _err:
4316 if (ctx is not None) and ctx.get("bered", False):
4318 offset, _value = self._strptime_bered(value_decoded)
4319 _value = _value - timedelta(seconds=offset)
4320 return self._dt_sanitize(_value), value
4321 except (TypeError, ValueError, OverflowError) as _err:
4324 "invalid %s format: %r" % (self.asn1_type_name, err),
4325 klass=self.__class__,
4327 if isinstance(value, self.__class__):
4328 return value._value, None
4329 if value.__class__ == datetime:
4330 return self._dt_sanitize(value), None
4331 raise InvalidValueType((self.__class__, datetime))
4333 def _pp_value(self):
4335 value = self._value.isoformat()
4336 if self.ber_encoded:
4337 value += " (%s)" % self.ber_raw
4340 def __unicode__(self):
4342 value = self._value.isoformat()
4343 if self.ber_encoded:
4344 value += " (%s)" % self.ber_raw
4346 return text_type(self._pp_value())
4348 def __getstate__(self):
4349 return UTCTimeState(
4350 *super(UTCTime, self).__getstate__(),
4351 **{"ber_raw": self.ber_raw}
4354 def __setstate__(self, state):
4355 super(UTCTime, self).__setstate__(state)
4356 self.ber_raw = state.ber_raw
4358 def __bytes__(self):
4359 self._assert_ready()
4360 return self._encode_time()
4362 def __eq__(self, their):
4363 if their.__class__ == binary_type:
4364 return self._encode_time() == their
4365 if their.__class__ == datetime:
4366 return self.todatetime() == their
4367 if not isinstance(their, self.__class__):
4370 self._value == their._value and
4371 self.tag == their.tag and
4372 self._expl == their._expl
4375 def _encode_time(self):
4376 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4379 self._assert_ready()
4380 value = self._encode_time()
4381 return b"".join((self.tag, len_encode(len(value)), value))
4383 def todatetime(self):
4387 return pp_console_row(next(self.pps()))
4389 def pps(self, decode_path=()):
4392 asn1_type_name=self.asn1_type_name,
4393 obj_name=self.__class__.__name__,
4394 decode_path=decode_path,
4395 value=self._pp_value(),
4396 optional=self.optional,
4397 default=self == self.default,
4398 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4399 expl=None if self._expl is None else tag_decode(self._expl),
4404 expl_offset=self.expl_offset if self.expled else None,
4405 expl_tlen=self.expl_tlen if self.expled else None,
4406 expl_llen=self.expl_llen if self.expled else None,
4407 expl_vlen=self.expl_vlen if self.expled else None,
4408 expl_lenindef=self.expl_lenindef,
4409 ber_encoded=self.ber_encoded,
4412 for pp in self.pps_lenindef(decode_path):
4416 class GeneralizedTime(UTCTime):
4417 """``GeneralizedTime`` datetime type
4419 This type is similar to :py:class:`pyderasn.UTCTime`.
4421 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4422 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4424 '20170930220750.000123Z'
4425 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4426 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4430 Only microsecond fractions are supported in DER encoding.
4431 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4432 higher precision values.
4436 BER encoded data can loss information (accuracy) during decoding
4437 because of float transformations.
4441 Local times (without explicit timezone specification) are treated
4442 as UTC one, no transformations are made.
4446 Zero year is unsupported.
4449 tag_default = tag_encode(24)
4450 asn1_type_name = "GeneralizedTime"
4452 def _dt_sanitize(self, value):
4455 def _strptime_bered(self, value):
4456 if len(value) < 4 + 3 * 2:
4457 raise ValueError("invalid GeneralizedTime")
4458 year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
4459 decoded = datetime(year, month, day, hour)
4460 offset, value = 0, value[10:]
4462 return offset, decoded
4463 if value[-1] == "Z":
4466 for char, sign in (("-", -1), ("+", 1)):
4467 idx = value.rfind(char)
4470 offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
4471 v = pureint(offset_raw)
4472 if len(offset_raw) == 4:
4473 offset, v = (60 * (v % 100)), v // 100
4475 raise ValueError("invalid UTC offset minutes")
4476 elif len(offset_raw) == 2:
4479 raise ValueError("invalid UTC offset")
4481 if offset > 14 * 3600:
4482 raise ValueError("too big UTC offset")
4486 return offset, decoded
4487 if value[0] in DECIMAL_SIGNS:
4489 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4492 raise ValueError("stripped minutes")
4493 decoded += timedelta(seconds=60 * pureint(value[:2]))
4496 return offset, decoded
4497 if value[0] in DECIMAL_SIGNS:
4499 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4502 raise ValueError("stripped seconds")
4503 decoded += timedelta(seconds=pureint(value[:2]))
4506 return offset, decoded
4507 if value[0] not in DECIMAL_SIGNS:
4508 raise ValueError("invalid format after seconds")
4510 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4513 def _strptime(self, value):
4515 if l == LEN_YYYYMMDDHHMMSSZ:
4516 # datetime.strptime's format: %Y%m%d%H%M%SZ
4517 if value[-1] != "Z":
4518 raise ValueError("non UTC timezone")
4519 return datetime(*str_to_time_fractions(value[:-1]))
4520 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4521 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4522 if value[-1] != "Z":
4523 raise ValueError("non UTC timezone")
4524 if value[14] != ".":
4525 raise ValueError("no fractions separator")
4528 raise ValueError("trailing zero")
4531 raise ValueError("only microsecond fractions are supported")
4532 us = pureint(us + ("0" * (6 - us_len)))
4533 year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
4534 return datetime(year, month, day, hour, minute, second, us)
4535 raise ValueError("invalid GeneralizedTime length")
4537 def _encode_time(self):
4539 encoded = value.strftime("%Y%m%d%H%M%S")
4540 if value.microsecond > 0:
4541 encoded += (".%06d" % value.microsecond).rstrip("0")
4542 return (encoded + "Z").encode("ascii")
4545 class GraphicString(CommonString):
4547 tag_default = tag_encode(25)
4548 encoding = "iso-8859-1"
4549 asn1_type_name = "GraphicString"
4552 class ISO646String(VisibleString):
4554 asn1_type_name = "ISO646String"
4557 class GeneralString(CommonString):
4559 tag_default = tag_encode(27)
4560 encoding = "iso-8859-1"
4561 asn1_type_name = "GeneralString"
4564 class UniversalString(CommonString):
4566 tag_default = tag_encode(28)
4567 encoding = "utf-32-be"
4568 asn1_type_name = "UniversalString"
4571 class BMPString(CommonString):
4573 tag_default = tag_encode(30)
4574 encoding = "utf-16-be"
4575 asn1_type_name = "BMPString"
4578 ChoiceState = namedtuple("ChoiceState", (
4592 ), **NAMEDTUPLE_KWARGS)
4596 """``CHOICE`` special type
4600 class GeneralName(Choice):
4602 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4603 ("dNSName", IA5String(impl=tag_ctxp(2))),
4606 >>> gn = GeneralName()
4608 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4609 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4610 >>> gn["dNSName"] = IA5String("bar.baz")
4611 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4612 >>> gn["rfc822Name"]
4615 [2] IA5String IA5 bar.baz
4618 >>> gn.value == gn["dNSName"]
4621 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4623 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4624 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4626 __slots__ = ("specs",)
4628 asn1_type_name = "CHOICE"
4641 :param value: set the value. Either ``(choice, value)`` tuple, or
4642 :py:class:`pyderasn.Choice` object
4643 :param bytes impl: can not be set, do **not** use it
4644 :param bytes expl: override default tag with ``EXPLICIT`` one
4645 :param default: set default value. Type same as in ``value``
4646 :param bool optional: is object ``OPTIONAL`` in sequence
4648 if impl is not None:
4649 raise ValueError("no implicit tag allowed for CHOICE")
4650 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4652 schema = getattr(self, "schema", ())
4653 if len(schema) == 0:
4654 raise ValueError("schema must be specified")
4656 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
4659 if value is not None:
4660 self._value = self._value_sanitize(value)
4661 if default is not None:
4662 default_value = self._value_sanitize(default)
4663 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4664 default_obj.specs = self.specs
4665 default_obj._value = default_value
4666 self.default = default_obj
4668 self._value = copy(default_obj._value)
4670 def _value_sanitize(self, value):
4671 if (value.__class__ == tuple) and len(value) == 2:
4673 spec = self.specs.get(choice)
4675 raise ObjUnknown(choice)
4676 if not isinstance(obj, spec.__class__):
4677 raise InvalidValueType((spec,))
4678 return (choice, spec(obj))
4679 if isinstance(value, self.__class__):
4681 raise InvalidValueType((self.__class__, tuple))
4685 return self._value is not None and self._value[1].ready
4689 return self.expl_lenindef or (
4690 (self._value is not None) and
4691 self._value[1].bered
4694 def __getstate__(self):
4711 def __setstate__(self, state):
4712 super(Choice, self).__setstate__(state)
4713 self.specs = state.specs
4714 self._value = state.value
4715 self._expl = state.expl
4716 self.default = state.default
4717 self.optional = state.optional
4718 self.offset = state.offset
4719 self.llen = state.llen
4720 self.vlen = state.vlen
4721 self.expl_lenindef = state.expl_lenindef
4722 self.lenindef = state.lenindef
4723 self.ber_encoded = state.ber_encoded
4725 def __eq__(self, their):
4726 if (their.__class__ == tuple) and len(their) == 2:
4727 return self._value == their
4728 if not isinstance(their, self.__class__):
4731 self.specs == their.specs and
4732 self._value == their._value
4742 return self.__class__(
4745 expl=self._expl if expl is None else expl,
4746 default=self.default if default is None else default,
4747 optional=self.optional if optional is None else optional,
4752 self._assert_ready()
4753 return self._value[0]
4757 self._assert_ready()
4758 return self._value[1]
4760 def __getitem__(self, key):
4761 if key not in self.specs:
4762 raise ObjUnknown(key)
4763 if self._value is None:
4765 choice, value = self._value
4770 def __setitem__(self, key, value):
4771 spec = self.specs.get(key)
4773 raise ObjUnknown(key)
4774 if not isinstance(value, spec.__class__):
4775 raise InvalidValueType((spec.__class__,))
4776 self._value = (key, spec(value))
4784 return self._value[1].decoded if self.ready else False
4787 self._assert_ready()
4788 return self._value[1].encode()
4790 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4791 for choice, spec in iteritems(self.specs):
4792 sub_decode_path = decode_path + (choice,)
4798 decode_path=sub_decode_path,
4801 _ctx_immutable=False,
4808 klass=self.__class__,
4809 decode_path=decode_path,
4812 if tag_only: # pragma: no cover
4814 value, tail = spec.decode(
4818 decode_path=sub_decode_path,
4820 _ctx_immutable=False,
4822 obj = self.__class__(
4825 default=self.default,
4826 optional=self.optional,
4827 _decoded=(offset, 0, value.fulllen),
4829 obj._value = (choice, value)
4833 value = pp_console_row(next(self.pps()))
4835 value = "%s[%r]" % (value, self.value)
4838 def pps(self, decode_path=()):
4841 asn1_type_name=self.asn1_type_name,
4842 obj_name=self.__class__.__name__,
4843 decode_path=decode_path,
4844 value=self.choice if self.ready else None,
4845 optional=self.optional,
4846 default=self == self.default,
4847 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4848 expl=None if self._expl is None else tag_decode(self._expl),
4853 expl_lenindef=self.expl_lenindef,
4857 yield self.value.pps(decode_path=decode_path + (self.choice,))
4858 for pp in self.pps_lenindef(decode_path):
4862 class PrimitiveTypes(Choice):
4863 """Predefined ``CHOICE`` for all generic primitive types
4865 It could be useful for general decoding of some unspecified values:
4867 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4868 OCTET STRING 3 bytes 666f6f
4869 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4873 schema = tuple((klass.__name__, klass()) for klass in (
4897 AnyState = namedtuple("AnyState", (
4910 ), **NAMEDTUPLE_KWARGS)
4914 """``ANY`` special type
4916 >>> Any(Integer(-123))
4918 >>> a = Any(OctetString(b"hello world").encode())
4919 ANY 040b68656c6c6f20776f726c64
4920 >>> hexenc(bytes(a))
4921 b'0x040x0bhello world'
4923 __slots__ = ("defined",)
4924 tag_default = tag_encode(0)
4925 asn1_type_name = "ANY"
4935 :param value: set the value. Either any kind of pyderasn's
4936 **ready** object, or bytes. Pay attention that
4937 **no** validation is performed is raw binary value
4939 :param bytes expl: override default tag with ``EXPLICIT`` one
4940 :param bool optional: is object ``OPTIONAL`` in sequence
4942 super(Any, self).__init__(None, expl, None, optional, _decoded)
4943 self._value = None if value is None else self._value_sanitize(value)
4946 def _value_sanitize(self, value):
4947 if value.__class__ == binary_type:
4949 if isinstance(value, self.__class__):
4951 if isinstance(value, Obj):
4952 return value.encode()
4953 raise InvalidValueType((self.__class__, Obj, binary_type))
4957 return self._value is not None
4961 if self.expl_lenindef or self.lenindef:
4963 if self.defined is None:
4965 return self.defined[1].bered
4967 def __getstate__(self):
4983 def __setstate__(self, state):
4984 super(Any, self).__setstate__(state)
4985 self._value = state.value
4986 self.tag = state.tag
4987 self._expl = state.expl
4988 self.optional = state.optional
4989 self.offset = state.offset
4990 self.llen = state.llen
4991 self.vlen = state.vlen
4992 self.expl_lenindef = state.expl_lenindef
4993 self.lenindef = state.lenindef
4994 self.ber_encoded = state.ber_encoded
4995 self.defined = state.defined
4997 def __eq__(self, their):
4998 if their.__class__ == binary_type:
4999 return self._value == their
5000 if issubclass(their.__class__, Any):
5001 return self._value == their._value
5010 return self.__class__(
5012 expl=self._expl if expl is None else expl,
5013 optional=self.optional if optional is None else optional,
5016 def __bytes__(self):
5017 self._assert_ready()
5025 self._assert_ready()
5028 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5030 t, tlen, lv = tag_strip(tlv)
5031 except DecodeError as err:
5032 raise err.__class__(
5034 klass=self.__class__,
5035 decode_path=decode_path,
5039 l, llen, v = len_decode(lv)
5040 except LenIndefForm as err:
5041 if not ctx.get("bered", False):
5042 raise err.__class__(
5044 klass=self.__class__,
5045 decode_path=decode_path,
5048 llen, vlen, v = 1, 0, lv[1:]
5049 sub_offset = offset + tlen + llen
5051 while v[:EOC_LEN].tobytes() != EOC:
5052 chunk, v = Any().decode(
5055 decode_path=decode_path + (str(chunk_i),),
5058 _ctx_immutable=False,
5060 vlen += chunk.tlvlen
5061 sub_offset += chunk.tlvlen
5063 tlvlen = tlen + llen + vlen + EOC_LEN
5064 obj = self.__class__(
5065 value=tlv[:tlvlen].tobytes(),
5067 optional=self.optional,
5068 _decoded=(offset, 0, tlvlen),
5071 obj.tag = t.tobytes()
5072 return obj, v[EOC_LEN:]
5073 except DecodeError as err:
5074 raise err.__class__(
5076 klass=self.__class__,
5077 decode_path=decode_path,
5081 raise NotEnoughData(
5082 "encoded length is longer than data",
5083 klass=self.__class__,
5084 decode_path=decode_path,
5087 tlvlen = tlen + llen + l
5088 v, tail = tlv[:tlvlen], v[l:]
5089 obj = self.__class__(
5092 optional=self.optional,
5093 _decoded=(offset, 0, tlvlen),
5095 obj.tag = t.tobytes()
5099 return pp_console_row(next(self.pps()))
5101 def pps(self, decode_path=()):
5104 asn1_type_name=self.asn1_type_name,
5105 obj_name=self.__class__.__name__,
5106 decode_path=decode_path,
5107 blob=self._value if self.ready else None,
5108 optional=self.optional,
5109 default=self == self.default,
5110 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5111 expl=None if self._expl is None else tag_decode(self._expl),
5116 expl_offset=self.expl_offset if self.expled else None,
5117 expl_tlen=self.expl_tlen if self.expled else None,
5118 expl_llen=self.expl_llen if self.expled else None,
5119 expl_vlen=self.expl_vlen if self.expled else None,
5120 expl_lenindef=self.expl_lenindef,
5121 lenindef=self.lenindef,
5124 defined_by, defined = self.defined or (None, None)
5125 if defined_by is not None:
5127 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5129 for pp in self.pps_lenindef(decode_path):
5133 ########################################################################
5134 # ASN.1 constructed types
5135 ########################################################################
5137 def get_def_by_path(defines_by_path, sub_decode_path):
5138 """Get define by decode path
5140 for path, define in defines_by_path:
5141 if len(path) != len(sub_decode_path):
5143 for p1, p2 in zip(path, sub_decode_path):
5144 if (not p1 is any) and (p1 != p2):
5150 def abs_decode_path(decode_path, rel_path):
5151 """Create an absolute decode path from current and relative ones
5153 :param decode_path: current decode path, starting point. Tuple of strings
5154 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5155 If first tuple's element is "/", then treat it as
5156 an absolute path, ignoring ``decode_path`` as
5157 starting point. Also this tuple can contain ".."
5158 elements, stripping the leading element from
5161 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5162 ("foo", "bar", "baz", "whatever")
5163 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5165 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5168 if rel_path[0] == "/":
5170 if rel_path[0] == "..":
5171 return abs_decode_path(decode_path[:-1], rel_path[1:])
5172 return decode_path + rel_path
5175 SequenceState = namedtuple("SequenceState", (
5189 ), **NAMEDTUPLE_KWARGS)
5192 class Sequence(Obj):
5193 """``SEQUENCE`` structure type
5195 You have to make specification of sequence::
5197 class Extension(Sequence):
5199 ("extnID", ObjectIdentifier()),
5200 ("critical", Boolean(default=False)),
5201 ("extnValue", OctetString()),
5204 Then, you can work with it as with dictionary.
5206 >>> ext = Extension()
5207 >>> Extension().specs
5209 ('extnID', OBJECT IDENTIFIER),
5210 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5211 ('extnValue', OCTET STRING),
5213 >>> ext["extnID"] = "1.2.3"
5214 Traceback (most recent call last):
5215 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5216 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5218 You can determine if sequence is ready to be encoded:
5223 Traceback (most recent call last):
5224 pyderasn.ObjNotReady: object is not ready: extnValue
5225 >>> ext["extnValue"] = OctetString(b"foobar")
5229 Value you want to assign, must have the same **type** as in
5230 corresponding specification, but it can have different tags,
5231 optional/default attributes -- they will be taken from specification
5234 class TBSCertificate(Sequence):
5236 ("version", Version(expl=tag_ctxc(0), default="v1")),
5239 >>> tbs = TBSCertificate()
5240 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5242 Assign ``None`` to remove value from sequence.
5244 You can set values in Sequence during its initialization:
5246 >>> AlgorithmIdentifier((
5247 ("algorithm", ObjectIdentifier("1.2.3")),
5248 ("parameters", Any(Null()))
5250 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5252 You can determine if value exists/set in the sequence and take its value:
5254 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5257 OBJECT IDENTIFIER 1.2.3
5259 But pay attention that if value has default, then it won't be (not
5260 in) in the sequence (because ``DEFAULT`` must not be encoded in
5261 DER), but you can read its value:
5263 >>> "critical" in ext, ext["critical"]
5264 (False, BOOLEAN False)
5265 >>> ext["critical"] = Boolean(True)
5266 >>> "critical" in ext, ext["critical"]
5267 (True, BOOLEAN True)
5269 All defaulted values are always optional.
5271 .. _allow_default_values_ctx:
5273 DER prohibits default value encoding and will raise an error if
5274 default value is unexpectedly met during decode.
5275 If :ref:`bered <bered_ctx>` context option is set, then no error
5276 will be raised, but ``bered`` attribute set. You can disable strict
5277 defaulted values existence validation by setting
5278 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5280 Two sequences are equal if they have equal specification (schema),
5281 implicit/explicit tagging and the same values.
5283 __slots__ = ("specs",)
5284 tag_default = tag_encode(form=TagFormConstructed, num=16)
5285 asn1_type_name = "SEQUENCE"
5297 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5299 schema = getattr(self, "schema", ())
5301 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
5304 if value is not None:
5305 if issubclass(value.__class__, Sequence):
5306 self._value = value._value
5307 elif hasattr(value, "__iter__"):
5308 for seq_key, seq_value in value:
5309 self[seq_key] = seq_value
5311 raise InvalidValueType((Sequence,))
5312 if default is not None:
5313 if not issubclass(default.__class__, Sequence):
5314 raise InvalidValueType((Sequence,))
5315 default_value = default._value
5316 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5317 default_obj.specs = self.specs
5318 default_obj._value = default_value
5319 self.default = default_obj
5321 self._value = copy(default_obj._value)
5325 for name, spec in iteritems(self.specs):
5326 value = self._value.get(name)
5337 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5339 return any(value.bered for value in itervalues(self._value))
5341 def __getstate__(self):
5342 return SequenceState(
5345 {k: copy(v) for k, v in iteritems(self._value)},
5358 def __setstate__(self, state):
5359 super(Sequence, self).__setstate__(state)
5360 self.specs = state.specs
5361 self._value = state.value
5362 self.tag = state.tag
5363 self._expl = state.expl
5364 self.default = state.default
5365 self.optional = state.optional
5366 self.offset = state.offset
5367 self.llen = state.llen
5368 self.vlen = state.vlen
5369 self.expl_lenindef = state.expl_lenindef
5370 self.lenindef = state.lenindef
5371 self.ber_encoded = state.ber_encoded
5373 def __eq__(self, their):
5374 if not isinstance(their, self.__class__):
5377 self.specs == their.specs and
5378 self.tag == their.tag and
5379 self._expl == their._expl and
5380 self._value == their._value
5391 return self.__class__(
5394 impl=self.tag if impl is None else impl,
5395 expl=self._expl if expl is None else expl,
5396 default=self.default if default is None else default,
5397 optional=self.optional if optional is None else optional,
5400 def __contains__(self, key):
5401 return key in self._value
5403 def __setitem__(self, key, value):
5404 spec = self.specs.get(key)
5406 raise ObjUnknown(key)
5408 self._value.pop(key, None)
5410 if not isinstance(value, spec.__class__):
5411 raise InvalidValueType((spec.__class__,))
5412 value = spec(value=value)
5413 if spec.default is not None and value == spec.default:
5414 self._value.pop(key, None)
5416 self._value[key] = value
5418 def __getitem__(self, key):
5419 value = self._value.get(key)
5420 if value is not None:
5422 spec = self.specs.get(key)
5424 raise ObjUnknown(key)
5425 if spec.default is not None:
5429 def _values_for_encoding(self):
5430 for name, spec in iteritems(self.specs):
5431 value = self._value.get(name)
5435 raise ObjNotReady(name)
5439 v = b"".join(v.encode() for v in self._values_for_encoding())
5440 return b"".join((self.tag, len_encode(len(v)), v))
5442 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5444 t, tlen, lv = tag_strip(tlv)
5445 except DecodeError as err:
5446 raise err.__class__(
5448 klass=self.__class__,
5449 decode_path=decode_path,
5454 klass=self.__class__,
5455 decode_path=decode_path,
5458 if tag_only: # pragma: no cover
5461 ctx_bered = ctx.get("bered", False)
5463 l, llen, v = len_decode(lv)
5464 except LenIndefForm as err:
5466 raise err.__class__(
5468 klass=self.__class__,
5469 decode_path=decode_path,
5472 l, llen, v = 0, 1, lv[1:]
5474 except DecodeError as err:
5475 raise err.__class__(
5477 klass=self.__class__,
5478 decode_path=decode_path,
5482 raise NotEnoughData(
5483 "encoded length is longer than data",
5484 klass=self.__class__,
5485 decode_path=decode_path,
5489 v, tail = v[:l], v[l:]
5491 sub_offset = offset + tlen + llen
5494 ctx_allow_default_values = ctx.get("allow_default_values", False)
5495 for name, spec in iteritems(self.specs):
5496 if spec.optional and (
5497 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5501 sub_decode_path = decode_path + (name,)
5503 value, v_tail = spec.decode(
5507 decode_path=sub_decode_path,
5509 _ctx_immutable=False,
5511 except TagMismatch as err:
5512 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5516 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5517 if defined is not None:
5518 defined_by, defined_spec = defined
5519 if issubclass(value.__class__, SequenceOf):
5520 for i, _value in enumerate(value):
5521 sub_sub_decode_path = sub_decode_path + (
5523 DecodePathDefBy(defined_by),
5525 defined_value, defined_tail = defined_spec.decode(
5526 memoryview(bytes(_value)),
5528 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5529 if value.expled else (value.tlen + value.llen)
5532 decode_path=sub_sub_decode_path,
5534 _ctx_immutable=False,
5536 if len(defined_tail) > 0:
5539 klass=self.__class__,
5540 decode_path=sub_sub_decode_path,
5543 _value.defined = (defined_by, defined_value)
5545 defined_value, defined_tail = defined_spec.decode(
5546 memoryview(bytes(value)),
5548 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5549 if value.expled else (value.tlen + value.llen)
5552 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5554 _ctx_immutable=False,
5556 if len(defined_tail) > 0:
5559 klass=self.__class__,
5560 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5563 value.defined = (defined_by, defined_value)
5565 value_len = value.fulllen
5567 sub_offset += value_len
5569 if spec.default is not None and value == spec.default:
5570 if ctx_bered or ctx_allow_default_values:
5574 "DEFAULT value met",
5575 klass=self.__class__,
5576 decode_path=sub_decode_path,
5579 values[name] = value
5581 spec_defines = getattr(spec, "defines", ())
5582 if len(spec_defines) == 0:
5583 defines_by_path = ctx.get("defines_by_path", ())
5584 if len(defines_by_path) > 0:
5585 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5586 if spec_defines is not None and len(spec_defines) > 0:
5587 for rel_path, schema in spec_defines:
5588 defined = schema.get(value, None)
5589 if defined is not None:
5590 ctx.setdefault("_defines", []).append((
5591 abs_decode_path(sub_decode_path[:-1], rel_path),
5595 if v[:EOC_LEN].tobytes() != EOC:
5598 klass=self.__class__,
5599 decode_path=decode_path,
5607 klass=self.__class__,
5608 decode_path=decode_path,
5611 obj = self.__class__(
5615 default=self.default,
5616 optional=self.optional,
5617 _decoded=(offset, llen, vlen),
5620 obj.lenindef = lenindef
5621 obj.ber_encoded = ber_encoded
5625 value = pp_console_row(next(self.pps()))
5627 for name in self.specs:
5628 _value = self._value.get(name)
5631 cols.append("%s: %s" % (name, repr(_value)))
5632 return "%s[%s]" % (value, "; ".join(cols))
5634 def pps(self, decode_path=()):
5637 asn1_type_name=self.asn1_type_name,
5638 obj_name=self.__class__.__name__,
5639 decode_path=decode_path,
5640 optional=self.optional,
5641 default=self == self.default,
5642 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5643 expl=None if self._expl is None else tag_decode(self._expl),
5648 expl_offset=self.expl_offset if self.expled else None,
5649 expl_tlen=self.expl_tlen if self.expled else None,
5650 expl_llen=self.expl_llen if self.expled else None,
5651 expl_vlen=self.expl_vlen if self.expled else None,
5652 expl_lenindef=self.expl_lenindef,
5653 lenindef=self.lenindef,
5654 ber_encoded=self.ber_encoded,
5657 for name in self.specs:
5658 value = self._value.get(name)
5661 yield value.pps(decode_path=decode_path + (name,))
5662 for pp in self.pps_lenindef(decode_path):
5666 class Set(Sequence):
5667 """``SET`` structure type
5669 Its usage is identical to :py:class:`pyderasn.Sequence`.
5671 .. _allow_unordered_set_ctx:
5673 DER prohibits unordered values encoding and will raise an error
5674 during decode. If :ref:`bered <bered_ctx>` context option is set,
5675 then no error will occur. Also you can disable strict values
5676 ordering check by setting ``"allow_unordered_set": True``
5677 :ref:`context <ctx>` option.
5680 tag_default = tag_encode(form=TagFormConstructed, num=17)
5681 asn1_type_name = "SET"
5684 raws = [v.encode() for v in self._values_for_encoding()]
5687 return b"".join((self.tag, len_encode(len(v)), v))
5689 def _specs_items(self):
5690 return iteritems(self.specs)
5692 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5694 t, tlen, lv = tag_strip(tlv)
5695 except DecodeError as err:
5696 raise err.__class__(
5698 klass=self.__class__,
5699 decode_path=decode_path,
5704 klass=self.__class__,
5705 decode_path=decode_path,
5711 ctx_bered = ctx.get("bered", False)
5713 l, llen, v = len_decode(lv)
5714 except LenIndefForm as err:
5716 raise err.__class__(
5718 klass=self.__class__,
5719 decode_path=decode_path,
5722 l, llen, v = 0, 1, lv[1:]
5724 except DecodeError as err:
5725 raise err.__class__(
5727 klass=self.__class__,
5728 decode_path=decode_path,
5732 raise NotEnoughData(
5733 "encoded length is longer than data",
5734 klass=self.__class__,
5738 v, tail = v[:l], v[l:]
5740 sub_offset = offset + tlen + llen
5743 ctx_allow_default_values = ctx.get("allow_default_values", False)
5744 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5745 value_prev = memoryview(v[:0])
5748 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5750 for name, spec in self._specs_items():
5751 sub_decode_path = decode_path + (name,)
5757 decode_path=sub_decode_path,
5760 _ctx_immutable=False,
5767 klass=self.__class__,
5768 decode_path=decode_path,
5771 value, v_tail = spec.decode(
5775 decode_path=sub_decode_path,
5777 _ctx_immutable=False,
5779 value_len = value.fulllen
5780 if value_prev.tobytes() > v[:value_len].tobytes():
5781 if ctx_bered or ctx_allow_unordered_set:
5785 "unordered " + self.asn1_type_name,
5786 klass=self.__class__,
5787 decode_path=sub_decode_path,
5790 if spec.default is None or value != spec.default:
5792 elif ctx_bered or ctx_allow_default_values:
5796 "DEFAULT value met",
5797 klass=self.__class__,
5798 decode_path=sub_decode_path,
5801 values[name] = value
5802 value_prev = v[:value_len]
5803 sub_offset += value_len
5806 obj = self.__class__(
5810 default=self.default,
5811 optional=self.optional,
5812 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5815 if v[:EOC_LEN].tobytes() != EOC:
5818 klass=self.__class__,
5819 decode_path=decode_path,
5825 for name, spec in iteritems(self.specs):
5826 if name not in values and not spec.optional:
5828 "%s value is not ready" % name,
5829 klass=self.__class__,
5830 decode_path=decode_path,
5833 obj.ber_encoded = ber_encoded
5837 SequenceOfState = namedtuple("SequenceOfState", (
5853 ), **NAMEDTUPLE_KWARGS)
5856 class SequenceOf(Obj):
5857 """``SEQUENCE OF`` sequence type
5859 For that kind of type you must specify the object it will carry on
5860 (bounds are for example here, not required)::
5862 class Ints(SequenceOf):
5867 >>> ints.append(Integer(123))
5868 >>> ints.append(Integer(234))
5870 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5871 >>> [int(i) for i in ints]
5873 >>> ints.append(Integer(345))
5874 Traceback (most recent call last):
5875 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5878 >>> ints[1] = Integer(345)
5880 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5882 Also you can initialize sequence with preinitialized values:
5884 >>> ints = Ints([Integer(123), Integer(234)])
5886 __slots__ = ("spec", "_bound_min", "_bound_max")
5887 tag_default = tag_encode(form=TagFormConstructed, num=16)
5888 asn1_type_name = "SEQUENCE OF"
5901 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5903 schema = getattr(self, "schema", None)
5905 raise ValueError("schema must be specified")
5907 self._bound_min, self._bound_max = getattr(
5911 ) if bounds is None else bounds
5913 if value is not None:
5914 self._value = self._value_sanitize(value)
5915 if default is not None:
5916 default_value = self._value_sanitize(default)
5917 default_obj = self.__class__(
5922 default_obj._value = default_value
5923 self.default = default_obj
5925 self._value = copy(default_obj._value)
5927 def _value_sanitize(self, value):
5928 if issubclass(value.__class__, SequenceOf):
5929 value = value._value
5930 elif hasattr(value, "__iter__"):
5933 raise InvalidValueType((self.__class__, iter))
5934 if not self._bound_min <= len(value) <= self._bound_max:
5935 raise BoundsError(self._bound_min, len(value), self._bound_max)
5937 if not isinstance(v, self.spec.__class__):
5938 raise InvalidValueType((self.spec.__class__,))
5943 return all(v.ready for v in self._value)
5947 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5949 return any(v.bered for v in self._value)
5951 def __getstate__(self):
5952 return SequenceOfState(
5955 [copy(v) for v in self._value],
5970 def __setstate__(self, state):
5971 super(SequenceOf, self).__setstate__(state)
5972 self.spec = state.spec
5973 self._value = state.value
5974 self._bound_min = state.bound_min
5975 self._bound_max = state.bound_max
5976 self.tag = state.tag
5977 self._expl = state.expl
5978 self.default = state.default
5979 self.optional = state.optional
5980 self.offset = state.offset
5981 self.llen = state.llen
5982 self.vlen = state.vlen
5983 self.expl_lenindef = state.expl_lenindef
5984 self.lenindef = state.lenindef
5985 self.ber_encoded = state.ber_encoded
5987 def __eq__(self, their):
5988 if isinstance(their, self.__class__):
5990 self.spec == their.spec and
5991 self.tag == their.tag and
5992 self._expl == their._expl and
5993 self._value == their._value
5995 if hasattr(their, "__iter__"):
5996 return self._value == list(their)
6008 return self.__class__(
6012 (self._bound_min, self._bound_max)
6013 if bounds is None else bounds
6015 impl=self.tag if impl is None else impl,
6016 expl=self._expl if expl is None else expl,
6017 default=self.default if default is None else default,
6018 optional=self.optional if optional is None else optional,
6021 def __contains__(self, key):
6022 return key in self._value
6024 def append(self, value):
6025 if not isinstance(value, self.spec.__class__):
6026 raise InvalidValueType((self.spec.__class__,))
6027 if len(self._value) + 1 > self._bound_max:
6030 len(self._value) + 1,
6033 self._value.append(value)
6036 self._assert_ready()
6037 return iter(self._value)
6040 self._assert_ready()
6041 return len(self._value)
6043 def __setitem__(self, key, value):
6044 if not isinstance(value, self.spec.__class__):
6045 raise InvalidValueType((self.spec.__class__,))
6046 self._value[key] = self.spec(value=value)
6048 def __getitem__(self, key):
6049 return self._value[key]
6051 def _values_for_encoding(self):
6052 return iter(self._value)
6055 v = b"".join(v.encode() for v in self._values_for_encoding())
6056 return b"".join((self.tag, len_encode(len(v)), v))
6058 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
6060 t, tlen, lv = tag_strip(tlv)
6061 except DecodeError as err:
6062 raise err.__class__(
6064 klass=self.__class__,
6065 decode_path=decode_path,
6070 klass=self.__class__,
6071 decode_path=decode_path,
6077 ctx_bered = ctx.get("bered", False)
6079 l, llen, v = len_decode(lv)
6080 except LenIndefForm as err:
6082 raise err.__class__(
6084 klass=self.__class__,
6085 decode_path=decode_path,
6088 l, llen, v = 0, 1, lv[1:]
6090 except DecodeError as err:
6091 raise err.__class__(
6093 klass=self.__class__,
6094 decode_path=decode_path,
6098 raise NotEnoughData(
6099 "encoded length is longer than data",
6100 klass=self.__class__,
6101 decode_path=decode_path,
6105 v, tail = v[:l], v[l:]
6107 sub_offset = offset + tlen + llen
6109 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6110 value_prev = memoryview(v[:0])
6114 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6116 sub_decode_path = decode_path + (str(len(_value)),)
6117 value, v_tail = spec.decode(
6121 decode_path=sub_decode_path,
6123 _ctx_immutable=False,
6125 value_len = value.fulllen
6127 if value_prev.tobytes() > v[:value_len].tobytes():
6128 if ctx_bered or ctx_allow_unordered_set:
6132 "unordered " + self.asn1_type_name,
6133 klass=self.__class__,
6134 decode_path=sub_decode_path,
6137 value_prev = v[:value_len]
6138 _value.append(value)
6139 sub_offset += value_len
6143 obj = self.__class__(
6146 bounds=(self._bound_min, self._bound_max),
6149 default=self.default,
6150 optional=self.optional,
6151 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6153 except BoundsError as err:
6156 klass=self.__class__,
6157 decode_path=decode_path,
6161 if v[:EOC_LEN].tobytes() != EOC:
6164 klass=self.__class__,
6165 decode_path=decode_path,
6170 obj.ber_encoded = ber_encoded
6175 pp_console_row(next(self.pps())),
6176 ", ".join(repr(v) for v in self._value),
6179 def pps(self, decode_path=()):
6182 asn1_type_name=self.asn1_type_name,
6183 obj_name=self.__class__.__name__,
6184 decode_path=decode_path,
6185 optional=self.optional,
6186 default=self == self.default,
6187 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6188 expl=None if self._expl is None else tag_decode(self._expl),
6193 expl_offset=self.expl_offset if self.expled else None,
6194 expl_tlen=self.expl_tlen if self.expled else None,
6195 expl_llen=self.expl_llen if self.expled else None,
6196 expl_vlen=self.expl_vlen if self.expled else None,
6197 expl_lenindef=self.expl_lenindef,
6198 lenindef=self.lenindef,
6199 ber_encoded=self.ber_encoded,
6202 for i, value in enumerate(self._value):
6203 yield value.pps(decode_path=decode_path + (str(i),))
6204 for pp in self.pps_lenindef(decode_path):
6208 class SetOf(SequenceOf):
6209 """``SET OF`` sequence type
6211 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6214 tag_default = tag_encode(form=TagFormConstructed, num=17)
6215 asn1_type_name = "SET OF"
6218 raws = [v.encode() for v in self._values_for_encoding()]
6221 return b"".join((self.tag, len_encode(len(v)), v))
6223 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6224 return super(SetOf, self)._decode(
6230 ordering_check=True,
6234 def obj_by_path(pypath): # pragma: no cover
6235 """Import object specified as string Python path
6237 Modules must be separated from classes/functions with ``:``.
6239 >>> obj_by_path("foo.bar:Baz")
6240 <class 'foo.bar.Baz'>
6241 >>> obj_by_path("foo.bar:Baz.boo")
6242 <classmethod 'foo.bar.Baz.boo'>
6244 mod, objs = pypath.rsplit(":", 1)
6245 from importlib import import_module
6246 obj = import_module(mod)
6247 for obj_name in objs.split("."):
6248 obj = getattr(obj, obj_name)
6252 def generic_decoder(): # pragma: no cover
6253 # All of this below is a big hack with self references
6254 choice = PrimitiveTypes()
6255 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6256 choice.specs["SetOf"] = SetOf(schema=choice)
6257 for i in six_xrange(31):
6258 choice.specs["SequenceOf%d" % i] = SequenceOf(
6262 choice.specs["Any"] = Any()
6264 # Class name equals to type name, to omit it from output
6265 class SEQUENCEOF(SequenceOf):
6273 with_decode_path=False,
6274 decode_path_only=(),
6276 def _pprint_pps(pps):
6278 if hasattr(pp, "_fields"):
6280 decode_path_only != () and
6281 pp.decode_path[:len(decode_path_only)] != decode_path_only
6284 if pp.asn1_type_name == Choice.asn1_type_name:
6286 pp_kwargs = pp._asdict()
6287 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6288 pp = _pp(**pp_kwargs)
6289 yield pp_console_row(
6294 with_colours=with_colours,
6295 with_decode_path=with_decode_path,
6296 decode_path_len_decrease=len(decode_path_only),
6298 for row in pp_console_blob(
6300 decode_path_len_decrease=len(decode_path_only),
6304 for row in _pprint_pps(pp):
6306 return "\n".join(_pprint_pps(obj.pps()))
6307 return SEQUENCEOF(), pprint_any
6310 def main(): # pragma: no cover
6312 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6313 parser.add_argument(
6317 help="Skip that number of bytes from the beginning",
6319 parser.add_argument(
6321 help="Python paths to dictionary with OIDs, comma separated",
6323 parser.add_argument(
6325 help="Python path to schema definition to use",
6327 parser.add_argument(
6328 "--defines-by-path",
6329 help="Python path to decoder's defines_by_path",
6331 parser.add_argument(
6333 action="store_true",
6334 help="Disallow BER encoding",
6336 parser.add_argument(
6337 "--print-decode-path",
6338 action="store_true",
6339 help="Print decode paths",
6341 parser.add_argument(
6342 "--decode-path-only",
6343 help="Print only specified decode path",
6345 parser.add_argument(
6347 action="store_true",
6348 help="Allow explicit tag out-of-bound",
6350 parser.add_argument(
6352 type=argparse.FileType("rb"),
6353 help="Path to DER file you want to decode",
6355 args = parser.parse_args()
6356 args.DERFile.seek(args.skip)
6357 der = memoryview(args.DERFile.read())
6358 args.DERFile.close()
6360 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6361 if args.oids else ()
6364 schema = obj_by_path(args.schema)
6365 from functools import partial
6366 pprinter = partial(pprint, big_blobs=True)
6368 schema, pprinter = generic_decoder()
6370 "bered": not args.nobered,
6371 "allow_expl_oob": args.allow_expl_oob,
6373 if args.defines_by_path is not None:
6374 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6375 obj, tail = schema().decode(der, ctx=ctx)
6376 from os import environ
6380 with_colours=environ.get("NO_COLOR") is None,
6381 with_decode_path=args.print_decode_path,
6383 () if args.decode_path_only is None else
6384 tuple(args.decode_path_only.split(":"))
6388 print("\nTrailing data: %s" % hexenc(tail))
6391 if __name__ == "__main__":