X-Git-Url: http://www.git.cypherpunks.ru/?p=pyderasn.git;a=blobdiff_plain;f=pyderasn.py;h=ed4071d8dffc5896bd0a92719baeee52220653b4;hp=2213e7804b60ae3b403dc09c25f6ad536ef08af0;hb=529183bf80e4796b3970d18e0fac490cd5865781;hpb=795d767d71d08311fe4e57efaa7521455db1d574 diff --git a/pyderasn.py b/pyderasn.py index 2213e78..ed4071d 100755 --- a/pyderasn.py +++ b/pyderasn.py @@ -382,7 +382,7 @@ DER. But you can optionally enable BER decoding with setting ``bered`` :ref:`context ` argument to True. Indefinite lengths and constructed primitive types should be parsed successfully. -* If object is encoded in BER form (not the DER one), then ``bered`` +* 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. * If object has an indefinite length encoding, then its ``lenindef`` @@ -391,6 +391,12 @@ constructed primitive types should be parsed successfully. contain it. * If object has an indefinite length encoded explicit tag, then ``expl_lenindef`` is set to True. +* If object has either any of BER-related encoding (explicit tag + indefinite length, object's indefinite length, BER-encoding) or any + underlying component has that kind of encoding, then ``bered`` + attribute is set to True. For example SignedData CMS can have + ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but + ``ContentInfo:content:signerInfos:*:signedAttrs`` won't. EOC (end-of-contents) token's length is taken in advance in object's value length. @@ -922,7 +928,7 @@ class Obj(object): "vlen", "expl_lenindef", "lenindef", - "bered", + "ber_encoded", ) def __init__( @@ -944,7 +950,7 @@ class Obj(object): self.default = None self.expl_lenindef = False self.lenindef = False - self.bered = False + self.ber_encoded = False @property def ready(self): # pragma: no cover @@ -952,6 +958,12 @@ class Obj(object): """ raise NotImplementedError() + @property + def bered(self): + """Is either object or any elements inside is BER encoded? + """ + return self.expl_lenindef or self.lenindef or self.ber_encoded + def _assert_ready(self): if not self.ready: raise ObjNotReady(self.__class__.__name__) @@ -1170,6 +1182,7 @@ class Obj(object): tlen=1, llen=1, vlen=0, + ber_encoded=True, bered=True, ) if self.expl_lenindef: @@ -1181,6 +1194,7 @@ class Obj(object): tlen=1, llen=1, vlen=0, + ber_encoded=True, bered=True, ) @@ -1232,6 +1246,7 @@ PP = namedtuple("PP", ( "expl_vlen", "expl_lenindef", "lenindef", + "ber_encoded", "bered", )) @@ -1256,6 +1271,7 @@ def _pp( expl_vlen=None, expl_lenindef=False, lenindef=False, + ber_encoded=False, bered=False, ): return PP( @@ -1278,6 +1294,7 @@ def _pp( expl_vlen, expl_lenindef, lenindef, + ber_encoded, bered, ) @@ -1305,7 +1322,9 @@ def pp_console_row( ), LENINDEF_PP_CHAR if pp.expl_lenindef else " ", ) - cols.append(_colourize(col, "red", with_colours, ())) + col = _colourize(col, "red", with_colours, ()) + col += _colourize("B", "red", with_colours) if pp.bered else " " + cols.append(col) col = "[%d,%d,%4d]%s" % ( pp.tlen, pp.llen, @@ -1342,7 +1361,7 @@ def pp_console_row( cols.append(_colourize(col, "blue", with_colours)) if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper(): cols.append(_colourize(pp.obj_name, "magenta", with_colours)) - if pp.bered: + if pp.ber_encoded: cols.append(_colourize("BER", "red", with_colours)) cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours)) if pp.value is not None: @@ -1373,7 +1392,7 @@ def pp_console_row( def pp_console_blob(pp, decode_path_len_decrease=0): - cols = [" " * len("XXXXXYYZ [X,X,XXXX]Z")] + cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")] decode_path_len = len(pp.decode_path) - decode_path_len_decrease if decode_path_len > 0: cols.append(" ." * (decode_path_len + 1)) @@ -1605,14 +1624,14 @@ class Boolean(Obj): offset=offset, ) first_octet = byte2int(v) - bered = False + ber_encoded = False if first_octet == 0: value = False elif first_octet == 0xFF: value = True elif ctx.get("bered", False): value = True - bered = True + ber_encoded = True else: raise DecodeError( "unacceptable Boolean value", @@ -1628,7 +1647,7 @@ class Boolean(Obj): optional=self.optional, _decoded=(offset, 1, 1), ) - obj.bered = bered + obj.ber_encoded = ber_encoded return obj, v[1:] def __repr__(self): @@ -1653,6 +1672,7 @@ class Boolean(Obj): 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): @@ -1979,6 +1999,7 @@ class Integer(Obj): 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, + bered=self.bered, ) for pp in self.pps_lenindef(decode_path): yield pp @@ -2402,7 +2423,7 @@ class BitString(Obj): _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)), ) obj.lenindef = lenindef - obj.bered = True + obj.ber_encoded = True return obj, (v[EOC_LEN:] if lenindef else v) raise TagMismatch( klass=self.__class__, @@ -2441,6 +2462,7 @@ class BitString(Obj): expl_vlen=self.expl_vlen if self.expled else None, expl_lenindef=self.expl_lenindef, lenindef=self.lenindef, + ber_encoded=self.ber_encoded, bered=self.bered, ) defined_by, defined = self.defined or (None, None) @@ -2758,7 +2780,7 @@ class OctetString(Obj): offset=offset, ) obj.lenindef = lenindef - obj.bered = True + obj.ber_encoded = True return obj, (v[EOC_LEN:] if lenindef else v) raise TagMismatch( klass=self.__class__, @@ -2790,6 +2812,7 @@ class OctetString(Obj): expl_vlen=self.expl_vlen if self.expled else None, expl_lenindef=self.expl_lenindef, lenindef=self.lenindef, + ber_encoded=self.ber_encoded, bered=self.bered, ) defined_by, defined = self.defined or (None, None) @@ -2930,6 +2953,7 @@ class Null(Obj): 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, + bered=self.bered, ) for pp in self.pps_lenindef(decode_path): yield pp @@ -3221,6 +3245,7 @@ class ObjectIdentifier(Obj): 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, + bered=self.bered, ) for pp in self.pps_lenindef(decode_path): yield pp @@ -3446,6 +3471,8 @@ class CommonString(OctetString): 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): yield pp @@ -3648,6 +3675,8 @@ class UTCTime(CommonString): 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): yield pp @@ -3846,6 +3875,13 @@ class Choice(Obj): def ready(self): return self._value is not None and self._value[1].ready + @property + def bered(self): + return self.expl_lenindef or ( + (self._value is not None) and + self._value[1].bered + ) + def copy(self): obj = self.__class__(schema=self.specs) obj._expl = self._expl @@ -3963,7 +3999,7 @@ class Choice(Obj): ) obj._value = (choice, value) obj.lenindef = value.lenindef - obj.bered = value.bered + obj.ber_encoded = value.ber_encoded return obj, tail def __repr__(self): @@ -3988,6 +4024,7 @@ class Choice(Obj): vlen=self.vlen, expl_lenindef=self.expl_lenindef, lenindef=self.lenindef, + ber_encoded=self.ber_encoded, bered=self.bered, ) if self.ready: @@ -4077,6 +4114,14 @@ class Any(Obj): def ready(self): return self._value is not None + @property + def bered(self): + if self.expl_lenindef or self.lenindef: + return True + if self.defined is None: + return False + return self.defined[1].bered + def copy(self): obj = self.__class__() obj._value = self._value @@ -4211,6 +4256,7 @@ class Any(Obj): expl_vlen=self.expl_vlen if self.expled else None, expl_lenindef=self.expl_lenindef, lenindef=self.lenindef, + bered=self.bered, ) defined_by, defined = self.defined or (None, None) if defined_by is not None: @@ -4408,6 +4454,12 @@ class Sequence(Obj): return False return True + @property + def bered(self): + if self.expl_lenindef or self.lenindef or self.ber_encoded: + return True + return any(value.bered for value in self._value.values()) + def copy(self): obj = self.__class__(schema=self.specs) obj.tag = self.tag @@ -4542,7 +4594,7 @@ class Sequence(Obj): vlen = 0 sub_offset = offset + tlen + llen values = {} - bered = False + ber_encoded = False ctx_allow_default_values = ctx.get("allow_default_values", False) for name, spec in self.specs.items(): if spec.optional and ( @@ -4617,7 +4669,7 @@ class Sequence(Obj): v = v_tail if spec.default is not None and value == spec.default: if ctx_bered or ctx_allow_default_values: - bered = True + ber_encoded = True else: raise DecodeError( "DEFAULT value met", @@ -4667,7 +4719,7 @@ class Sequence(Obj): ) obj._value = values obj.lenindef = lenindef - obj.bered = bered + obj.ber_encoded = ber_encoded return obj, tail def __repr__(self): @@ -4699,6 +4751,8 @@ class Sequence(Obj): expl_vlen=self.expl_vlen if self.expled else None, expl_lenindef=self.expl_lenindef, lenindef=self.lenindef, + ber_encoded=self.ber_encoded, + bered=self.bered, ) for name in self.specs: value = self._value.get(name) @@ -4782,7 +4836,7 @@ class Set(Sequence): vlen = 0 sub_offset = offset + tlen + llen values = {} - bered = False + ber_encoded = False ctx_allow_default_values = ctx.get("allow_default_values", False) ctx_allow_unordered_set = ctx.get("allow_unordered_set", False) value_prev = memoryview(v[:0]) @@ -4820,7 +4874,7 @@ class Set(Sequence): value_len = value.fulllen if value_prev.tobytes() > v[:value_len].tobytes(): if ctx_bered or ctx_allow_unordered_set: - bered = True + ber_encoded = True else: raise DecodeError( "unordered " + self.asn1_type_name, @@ -4831,7 +4885,7 @@ class Set(Sequence): if spec.default is None or value != spec.default: pass elif ctx_bered or ctx_allow_default_values: - bered = True + ber_encoded = True else: raise DecodeError( "DEFAULT value met", @@ -4870,7 +4924,7 @@ class Set(Sequence): decode_path=decode_path, offset=offset, ) - obj.bered = bered + obj.ber_encoded = ber_encoded return obj, tail @@ -4969,6 +5023,12 @@ class SequenceOf(Obj): def ready(self): return all(v.ready for v in self._value) + @property + def bered(self): + if self.expl_lenindef or self.lenindef or self.ber_encoded: + return True + return any(v.bered for v in self._value) + def copy(self): obj = self.__class__(schema=self.spec) obj._bound_min = self._bound_min @@ -5107,7 +5167,7 @@ class SequenceOf(Obj): _value = [] ctx_allow_unordered_set = ctx.get("allow_unordered_set", False) value_prev = memoryview(v[:0]) - bered = False + ber_encoded = False spec = self.spec while len(v) > 0: if lenindef and v[:EOC_LEN].tobytes() == EOC: @@ -5124,7 +5184,7 @@ class SequenceOf(Obj): if ordering_check: if value_prev.tobytes() > v[:value_len].tobytes(): if ctx_bered or ctx_allow_unordered_set: - bered = True + ber_encoded = True else: raise DecodeError( "unordered " + self.asn1_type_name, @@ -5165,7 +5225,7 @@ class SequenceOf(Obj): ) obj.lenindef = True tail = v[EOC_LEN:] - obj.bered = bered + obj.ber_encoded = ber_encoded return obj, tail def __repr__(self): @@ -5193,6 +5253,8 @@ class SequenceOf(Obj): expl_vlen=self.expl_vlen if self.expled else None, expl_lenindef=self.expl_lenindef, lenindef=self.lenindef, + ber_encoded=self.ber_encoded, + bered=self.bered, ) for i, value in enumerate(self._value): yield value.pps(decode_path=decode_path + (str(i),))