X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=pyderasn.py;h=162c1404a3af15ddbae345c63d391f8d34fb45e2;hb=498f47100e12f1bef247b29460ac4621fa0fc9f9;hp=c9d6a116044b5515b0f75b6b5271327345106f6d;hpb=659eb0e090ad8c9209c4e5b030806125509844f9;p=pyderasn.git diff --git a/pyderasn.py b/pyderasn.py index c9d6a11..162c140 100755 --- a/pyderasn.py +++ b/pyderasn.py @@ -665,6 +665,11 @@ parse the CRL above with fully assembled ``RevokedCertificate``:: ): print("serial number:", int(obj["userCertificate"])) +.. note:: + + SEQUENCE/SET values with DEFAULT specified are automatically decoded + without evgen mode. + .. _mmap: mmap-ed file @@ -763,6 +768,8 @@ forcefully encoded in DER during CER encoding, by specifying bounds = (1, 32) der_forced = True +.. _agg_octet_string: + agg_octet_string ________________ @@ -910,7 +917,7 @@ _______ Integer _______ .. autoclass:: pyderasn.Integer - :members: __init__, named + :members: __init__, named, tohex BitString _________ @@ -1178,7 +1185,7 @@ except ImportError: # pragma: no cover def colored(what, *args, **kwargs): return what -__version__ = "7.2" +__version__ = "7.4" __all__ = ( "agg_octet_string", @@ -1188,6 +1195,7 @@ __all__ = ( "Boolean", "BoundsError", "Choice", + "colonize_hex", "DecodeError", "DecodePathDefBy", "encode2pass", @@ -1759,13 +1767,13 @@ class Obj(object): @property def tlen(self): - """See :ref:`decoding` + """.. seealso:: :ref:`decoding` """ return len(self.tag) @property def tlvlen(self): - """See :ref:`decoding` + """.. seealso:: :ref:`decoding` """ return self.tlen + self.llen + self.vlen @@ -1921,7 +1929,8 @@ class Obj(object): That method is identical to :py:meth:`pyderasn.Obj.decode`, but it returns the generator producing ``(decode_path, obj, tail)`` - values. See :ref:`evgen mode `. + values. + .. seealso:: :ref:`evgen mode `. """ if ctx is None: ctx = {} @@ -2070,25 +2079,25 @@ class Obj(object): @property def expled(self): - """See :ref:`decoding` + """.. seealso:: :ref:`decoding` """ return self._expl is not None @property def expl_tag(self): - """See :ref:`decoding` + """.. seealso:: :ref:`decoding` """ return self._expl @property def expl_tlen(self): - """See :ref:`decoding` + """.. seealso:: :ref:`decoding` """ return len(self._expl) @property def expl_llen(self): - """See :ref:`decoding` + """.. seealso:: :ref:`decoding` """ if self.expl_lenindef: return 1 @@ -2096,31 +2105,31 @@ class Obj(object): @property def expl_offset(self): - """See :ref:`decoding` + """.. seealso:: :ref:`decoding` """ return self.offset - self.expl_tlen - self.expl_llen @property def expl_vlen(self): - """See :ref:`decoding` + """.. seealso:: :ref:`decoding` """ return self.tlvlen @property def expl_tlvlen(self): - """See :ref:`decoding` + """.. seealso:: :ref:`decoding` """ return self.expl_tlen + self.expl_llen + self.expl_vlen @property def fulloffset(self): - """See :ref:`decoding` + """.. seealso:: :ref:`decoding` """ return self.expl_offset if self.expled else self.offset @property def fulllen(self): - """See :ref:`decoding` + """.. seealso:: :ref:`decoding` """ return self.expl_tlvlen if self.expled else self.tlvlen @@ -2369,13 +2378,8 @@ def pp_console_row( cols.append(_colourize("(%s)" % oid_name, "green", with_colours)) break 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, + "(%s)" % colonize_hex(pp.obj.tohex()), "green", with_colours, )) if with_blob: if pp.blob.__class__ == binary_type: @@ -2842,6 +2846,16 @@ class Integer(Obj): self._assert_ready() return int(self._value) + def tohex(self): + """Hexadecimal representation + + Use :py:func:`pyderasn.colonize_hex` for colonizing it. + """ + hex_repr = hex(int(self))[2:].upper() + if len(hex_repr) % 2 != 0: + hex_repr = "0" + hex_repr + return hex_repr + def __hash__(self): self._assert_ready() return hash(b"".join(( @@ -2933,7 +2947,6 @@ class Integer(Obj): else: break return octets - return b"".join((self.tag, len_encode(len(octets)), octets)) def _encode(self): octets = self._encode_payload() @@ -4074,6 +4087,8 @@ def agg_octet_string(evgens, decode_path, raw, writer): :param writer: buffer.write where string is going to be saved :param writer: where string is going to be saved. Must comply with ``io.RawIOBase.write`` behaviour + + .. seealso:: :ref:`agg_octet_string` """ decode_path_len = len(decode_path) for dp, obj, _ in evgens: @@ -4291,7 +4306,9 @@ class ObjectIdentifier(Obj): tuple element is ``{OID: pyderasn.Obj()}`` dictionary, mapping between current OID value and structure applied to defined field. - :ref:`Read about DEFINED BY ` + + .. seealso:: :ref:`definedby` + :param bytes impl: override default tag with ``IMPLICIT`` one :param bytes expl: override default tag with ``EXPLICIT`` one :param default: set default value. Type same as in ``value`` @@ -6188,11 +6205,10 @@ class Sequence(SequenceEncode1stMixing, Obj): defaulted values existence validation by setting ``"allow_default_values": True`` :ref:`context ` option. - .. warning:: - - Check for default value existence is not performed in - ``evgen_mode``, because previously decoded values are not stored - in memory, to be able to compare them. + All values with DEFAULT specified are decoded atomically in + :ref:`evgen mode `. If DEFAULT value is some kind of + SEQUENCE, then it will be yielded as a single element, not + disassembled. That is required for DEFAULT existence check. Two sequences are equal if they have equal specification (schema), implicit/explicit tagging and the same values. @@ -6418,9 +6434,10 @@ class Sequence(SequenceEncode1stMixing, Obj): len(v) == 0 ): continue + spec_defaulted = spec.default is not None sub_decode_path = decode_path + (name,) try: - if evgen_mode: + if evgen_mode and not spec_defaulted: for _decode_path, value, v_tail in spec.decode_evgen( v, sub_offset, @@ -6498,9 +6515,10 @@ class Sequence(SequenceEncode1stMixing, Obj): vlen += value_len sub_offset += value_len v = v_tail - if not evgen_mode: - if spec.default is not None and value == spec.default: - # This will not work in evgen_mode + if spec_defaulted: + if evgen_mode: + yield sub_decode_path, value, v_tail + if value == spec.default: if ctx_bered or ctx_allow_default_values: ber_encoded = True else: @@ -6510,6 +6528,7 @@ class Sequence(SequenceEncode1stMixing, Obj): decode_path=sub_decode_path, offset=sub_offset, ) + if not evgen_mode: values[name] = value spec_defines = getattr(spec, "defines", ()) if len(spec_defines) == 0: @@ -6709,7 +6728,8 @@ class Set(Sequence, SequenceEncode1stMixing): decode_path=decode_path, offset=offset, ) - if evgen_mode: + spec_defaulted = spec.default is not None + if evgen_mode and not spec_defaulted: for _decode_path, value, v_tail in spec.decode_evgen( v, sub_offset, @@ -6741,17 +6761,20 @@ class Set(Sequence, SequenceEncode1stMixing): decode_path=sub_decode_path, offset=sub_offset, ) - if spec.default is None or value != spec.default: - pass - elif ctx_bered or ctx_allow_default_values: - ber_encoded = True - else: - raise DecodeError( - "DEFAULT value met", - klass=self.__class__, - decode_path=sub_decode_path, - offset=sub_offset, - ) + if spec_defaulted: + if evgen_mode: + yield sub_decode_path, value, v_tail + if value != spec.default: + pass + elif ctx_bered or ctx_allow_default_values: + ber_encoded = True + else: + raise DecodeError( + "DEFAULT value met", + klass=self.__class__, + decode_path=sub_decode_path, + offset=sub_offset, + ) values[name] = value del _specs_items[name] tag_order_prev = value_tag_order @@ -7476,4 +7499,5 @@ def main(): # pragma: no cover if __name__ == "__main__": + from pyderasn import * main()