#!/usr/bin/env python
# coding: utf-8
# PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
-# Copyright (C) 2017-2018 Sergey Matveev <stargrave@stargrave.org>
+# Copyright (C) 2017-2019 Sergey Matveev <stargrave@stargrave.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
* If object is encoded in BER form (not the DER one), then ``ber_encoded``
attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
- STRING``, ``SEQUENCE``, ``SET``, ``SET OF`` can contain it.
+ STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``
+ can contain it.
* If object has an indefinite length encoding, then its ``lenindef``
attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
-------
.. autofunction:: pyderasn.abs_decode_path
+.. autofunction:: pyderasn.colonize_hex
.. autofunction:: pyderasn.hexenc
.. autofunction:: pyderasn.hexdec
.. autofunction:: pyderasn.tag_encode
from codecs import getencoder
from collections import namedtuple
from collections import OrderedDict
+from copy import copy
from datetime import datetime
from math import ceil
from os import environ
class ASN1Error(ValueError):
pass
+
class DecodeError(ASN1Error):
def __init__(self, msg="", klass=None, decode_path=(), offset=0):
"""
decode_path=(),
ctx=None,
tag_only=False,
+ _ctx_immutable=True,
):
"""Decode the data
:param tag_only: decode only the tag, without length and contents
(used only in Choice and Set structures, trying to
determine if tag satisfies the scheme)
+ :param _ctx_immutable: do we need to copy ``ctx`` before using it
:returns: (Obj, remaining data)
"""
if ctx is None:
ctx = {}
+ elif _ctx_immutable:
+ ctx = copy(ctx)
tlv = memoryview(data)
if self._expl is None:
result = self._decode(
########################################################################
PP = namedtuple("PP", (
+ "obj",
"asn1_type_name",
"obj_name",
"decode_path",
def _pp(
+ obj=None,
asn1_type_name="unknown",
obj_name="unknown",
decode_path=(),
bered=False,
):
return PP(
+ obj,
asn1_type_name,
obj_name,
decode_path,
return colored(what, colour, attrs=attrs) if with_colours else what
+def colonize_hex(hexed):
+ """Separate hexadecimal string with colons
+ """
+ return ":".join(hexed[i:i + 2] for i in range(0, len(hexed), 2))
+
+
def pp_console_row(
pp,
oids=None,
value in oids
):
cols.append(_colourize("(%s)" % oids[value], "green", with_colours))
+ if pp.asn1_type_name == Integer.asn1_type_name:
+ hex_repr = hex(int(pp.obj._value))[2:].upper()
+ if len(hex_repr) % 2 != 0:
+ hex_repr = "0" + hex_repr
+ cols.append(_colourize(
+ "(%s)" % colonize_hex(hex_repr),
+ "green",
+ with_colours,
+ ))
if with_blob:
if isinstance(pp.blob, binary_type):
cols.append(hexenc(pp.blob))
blob = hexenc(pp.blob).upper()
for i in range(0, len(blob), 32):
chunk = blob[i:i + 32]
- yield " ".join(cols + [":".join(
- chunk[j:j + 2] for j in range(0, len(chunk), 2)
- )])
+ yield " ".join(cols + [colonize_hex(chunk)])
elif isinstance(pp.blob, tuple):
yield " ".join(cols + [", ".join(pp.blob)])
obj.offset = self.offset
obj.llen = self.llen
obj.vlen = self.vlen
+ obj.expl_lenindef = self.expl_lenindef
+ obj.lenindef = self.lenindef
+ obj.ber_encoded = self.ber_encoded
return obj
def __nonzero__(self):
def pps(self, decode_path=()):
yield _pp(
+ obj=self,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
obj.offset = self.offset
obj.llen = self.llen
obj.vlen = self.vlen
+ obj.expl_lenindef = self.expl_lenindef
+ obj.lenindef = self.lenindef
+ obj.ber_encoded = self.ber_encoded
return obj
def __int__(self):
def pps(self, decode_path=()):
yield _pp(
+ obj=self,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
obj.offset = self.offset
obj.llen = self.llen
obj.vlen = self.vlen
+ obj.expl_lenindef = self.expl_lenindef
+ obj.lenindef = self.lenindef
+ obj.ber_encoded = self.ber_encoded
return obj
def __iter__(self):
decode_path=sub_decode_path,
leavemm=True,
ctx=ctx,
+ _ctx_immutable=False,
)
except TagMismatch:
raise DecodeError(
if len(self.specs) > 0:
blob = tuple(self.named)
yield _pp(
+ obj=self,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
obj.offset = self.offset
obj.llen = self.llen
obj.vlen = self.vlen
+ obj.expl_lenindef = self.expl_lenindef
+ obj.lenindef = self.lenindef
+ obj.ber_encoded = self.ber_encoded
return obj
def __bytes__(self):
decode_path=sub_decode_path,
leavemm=True,
ctx=ctx,
+ _ctx_immutable=False,
)
except TagMismatch:
raise DecodeError(
def pps(self, decode_path=()):
yield _pp(
+ obj=self,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
obj.offset = self.offset
obj.llen = self.llen
obj.vlen = self.vlen
+ obj.expl_lenindef = self.expl_lenindef
+ obj.lenindef = self.lenindef
+ obj.ber_encoded = self.ber_encoded
return obj
def __eq__(self, their):
def pps(self, decode_path=()):
yield _pp(
+ obj=self,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
obj.offset = self.offset
obj.llen = self.llen
obj.vlen = self.vlen
+ obj.expl_lenindef = self.expl_lenindef
+ obj.lenindef = self.lenindef
+ obj.ber_encoded = self.ber_encoded
return obj
def __iter__(self):
)
v, tail = v[:l], v[l:]
arcs = []
+ ber_encoded = False
while len(v) > 0:
i = 0
arc = 0
while True:
octet = indexbytes(v, i)
+ if i == 0 and octet == 0x80:
+ if ctx.get("bered", False):
+ ber_encoded = True
+ else:
+ raise DecodeError("non normalized arc encoding")
arc = (arc << 7) | (octet & 0x7F)
if octet & 0x80 == 0:
arcs.append(arc)
optional=self.optional,
_decoded=(offset, llen, l),
)
+ if ber_encoded:
+ obj.ber_encoded = True
return obj, tail
def __repr__(self):
def pps(self, decode_path=()):
yield _pp(
+ obj=self,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
expl_llen=self.expl_llen if self.expled else None,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
+ ber_encoded=self.ber_encoded,
bered=self.bered,
)
for pp in self.pps_lenindef(decode_path):
obj.offset = self.offset
obj.llen = self.llen
obj.vlen = self.vlen
+ obj.expl_lenindef = self.expl_lenindef
+ obj.lenindef = self.lenindef
+ obj.ber_encoded = self.ber_encoded
return obj
def __call__(
if self.ready:
value = hexenc(bytes(self)) if no_unicode else self.__unicode__()
yield _pp(
+ obj=self,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
def pps(self, decode_path=()):
yield _pp(
+ obj=self,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
obj.offset = self.offset
obj.llen = self.llen
obj.vlen = self.vlen
+ obj.expl_lenindef = self.expl_lenindef
+ obj.lenindef = self.lenindef
+ obj.ber_encoded = self.ber_encoded
value = self._value
if value is not None:
obj._value = (value[0], value[1].copy())
decode_path=sub_decode_path,
ctx=ctx,
tag_only=True,
+ _ctx_immutable=False,
)
except TagMismatch:
continue
leavemm=True,
decode_path=sub_decode_path,
ctx=ctx,
+ _ctx_immutable=False,
)
obj = self.__class__(
schema=self.specs,
def pps(self, decode_path=()):
yield _pp(
+ obj=self,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
obj.offset = self.offset
obj.llen = self.llen
obj.vlen = self.vlen
+ obj.expl_lenindef = self.expl_lenindef
+ obj.lenindef = self.lenindef
+ obj.ber_encoded = self.ber_encoded
return obj
def __eq__(self, their):
decode_path=decode_path + (str(chunk_i),),
leavemm=True,
ctx=ctx,
+ _ctx_immutable=False,
)
vlen += chunk.tlvlen
sub_offset += chunk.tlvlen
def pps(self, decode_path=()):
yield _pp(
+ obj=self,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
obj.offset = self.offset
obj.llen = self.llen
obj.vlen = self.vlen
+ obj.expl_lenindef = self.expl_lenindef
+ obj.lenindef = self.lenindef
+ obj.ber_encoded = self.ber_encoded
obj._value = {k: v.copy() for k, v in self._value.items()}
return obj
leavemm=True,
decode_path=sub_decode_path,
ctx=ctx,
+ _ctx_immutable=False,
)
except TagMismatch:
if spec.optional:
leavemm=True,
decode_path=sub_sub_decode_path,
ctx=ctx,
+ _ctx_immutable=False,
)
if len(defined_tail) > 0:
raise DecodeError(
leavemm=True,
decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
ctx=ctx,
+ _ctx_immutable=False,
)
if len(defined_tail) > 0:
raise DecodeError(
def pps(self, decode_path=()):
yield _pp(
+ obj=self,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
decode_path=sub_decode_path,
ctx=ctx,
tag_only=True,
+ _ctx_immutable=False,
)
except TagMismatch:
continue
leavemm=True,
decode_path=sub_decode_path,
ctx=ctx,
+ _ctx_immutable=False,
)
value_len = value.fulllen
if value_prev.tobytes() > v[:value_len].tobytes():
obj.offset = self.offset
obj.llen = self.llen
obj.vlen = self.vlen
+ obj.expl_lenindef = self.expl_lenindef
+ obj.lenindef = self.lenindef
+ obj.ber_encoded = self.ber_encoded
obj._value = [v.copy() for v in self._value]
return obj
leavemm=True,
decode_path=sub_decode_path,
ctx=ctx,
+ _ctx_immutable=False,
)
value_len = value.fulllen
if ordering_check:
def pps(self, decode_path=()):
yield _pp(
+ obj=self,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,