X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=pyderasn.py;h=15ca386b89894c7c4278fc2914f5ca9c3b44e199;hb=858cfc57f01b2b31b707fb4f808319ab877003dc;hp=4a1244c6d469d12a172df108c93b68bf325ce010;hpb=0ebead641ed9643e3d26275fc7d3e9bd89eee0c6;p=pyderasn.git diff --git a/pyderasn.py b/pyderasn.py index 4a1244c..15ca386 100755 --- a/pyderasn.py +++ b/pyderasn.py @@ -962,6 +962,14 @@ _______________ .. autoclass:: pyderasn.PrintableString :members: __init__, allow_asterisk, allow_ampersand +IA5String +_________ +.. autoclass:: pyderasn.IA5String + +VisibleString +_____________ +.. autoclass:: pyderasn.VisibleString + UTCTime _______ .. autoclass:: pyderasn.UTCTime @@ -1193,7 +1201,7 @@ except ImportError: # pragma: no cover def colored(what, *args, **kwargs): return what -__version__ = "7.4" +__version__ = "7.6" __all__ = ( "agg_octet_string", @@ -1287,11 +1295,13 @@ def file_mmaped(fd): """ return memoryview(mmap(fd.fileno(), 0, prot=PROT_READ)) + def pureint(value): if not set(value) <= DECIMALS: raise ValueError("non-pure integer") return int(value) + def fractions2float(fractions_raw): pureint(fractions_raw) return float("0." + fractions_raw) @@ -1304,7 +1314,7 @@ def get_def_by_path(defines_by_path, sub_decode_path): if len(path) != len(sub_decode_path): continue for p1, p2 in zip(path, sub_decode_path): - if (not p1 is any) and (p1 != p2): + if (p1 is not any) and (p1 != p2): break else: return define @@ -1963,7 +1973,7 @@ class Obj(object): yield None return _decode_path, obj, tail = result - if not _decode_path is decode_path: + if _decode_path is not decode_path: yield result else: try: @@ -2005,7 +2015,7 @@ class Obj(object): yield None return _decode_path, obj, tail = result - if not _decode_path is decode_path: + if _decode_path is not decode_path: yield result eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:] if eoc_expected.tobytes() != EOC: @@ -2044,7 +2054,7 @@ class Obj(object): yield None return _decode_path, obj, tail = result - if not _decode_path is decode_path: + if _decode_path is not decode_path: yield result if obj.tlvlen < l and not ctx.get("allow_expl_oob", False): raise DecodeError( @@ -3373,7 +3383,7 @@ class BitString(Obj): int2byte(0), octets[offset:offset + 999], ))) - tail = octets[offset+999:] + tail = octets[offset + 999:] if len(tail) > 0: tail = int2byte((8 - bit_len % 8) % 8) + tail write_full(writer, b"".join(( @@ -3833,7 +3843,7 @@ class OctetString(Obj): LEN1K, octets[offset:offset + 1000], ))) - tail = octets[offset+1000:] + tail = octets[offset + 1000:] if len(tail) > 0: write_full(writer, b"".join(( OctetString.tag_default, @@ -4708,27 +4718,25 @@ class CommonString(OctetString): :header-rows: 1 * - Class - - Text Encoding + - Text Encoding, validation * - :py:class:`pyderasn.UTF8String` - utf-8 * - :py:class:`pyderasn.NumericString` - - ascii + - proper alphabet validation * - :py:class:`pyderasn.PrintableString` - - ascii + - proper alphabet validation * - :py:class:`pyderasn.TeletexString` - - ascii + - iso-8859-1 * - :py:class:`pyderasn.T61String` - - ascii + - iso-8859-1 * - :py:class:`pyderasn.VideotexString` - iso-8859-1 * - :py:class:`pyderasn.IA5String` - - ascii + - proper alphabet validation * - :py:class:`pyderasn.GraphicString` - iso-8859-1 - * - :py:class:`pyderasn.VisibleString` - - ascii - * - :py:class:`pyderasn.ISO646String` - - ascii + * - :py:class:`pyderasn.VisibleString`, :py:class:`pyderasn.ISO646String` + - proper alphabet validation * - :py:class:`pyderasn.GeneralString` - iso-8859-1 * - :py:class:`pyderasn.UniversalString` @@ -4836,6 +4844,12 @@ class AllowableCharsMixin(object): return self._allowable_chars return frozenset(six_unichr(c) for c in self._allowable_chars) + def _value_sanitize(self, value): + value = super(AllowableCharsMixin, self)._value_sanitize(value) + if not frozenset(value) <= self._allowable_chars: + raise DecodeError("non satisfying alphabet value") + return value + class NumericString(AllowableCharsMixin, CommonString): """Numeric string @@ -4852,12 +4866,6 @@ class NumericString(AllowableCharsMixin, CommonString): asn1_type_name = "NumericString" _allowable_chars = frozenset(digits.encode("ascii") + b" ") - def _value_sanitize(self, value): - value = super(NumericString, self)._value_sanitize(value) - if not frozenset(value) <= self._allowable_chars: - raise DecodeError("non-numeric value") - return value - PrintableStringState = namedtuple( "PrintableStringState", @@ -4925,12 +4933,6 @@ class PrintableString(AllowableCharsMixin, CommonString): """ return self._ampersand <= self._allowable_chars - def _value_sanitize(self, value): - value = super(PrintableString, self)._value_sanitize(value) - if not frozenset(value) <= self._allowable_chars: - raise DecodeError("non-printable value") - return value - def __getstate__(self): return PrintableStringState( *super(PrintableString, self).__getstate__(), @@ -4968,7 +4970,7 @@ class PrintableString(AllowableCharsMixin, CommonString): class TeletexString(CommonString): __slots__ = () tag_default = tag_encode(20) - encoding = "ascii" + encoding = "iso-8859-1" asn1_type_name = "TeletexString" @@ -4984,11 +4986,27 @@ class VideotexString(CommonString): asn1_type_name = "VideotexString" -class IA5String(CommonString): +class IA5String(AllowableCharsMixin, CommonString): + """IA5 string + + Its value is properly sanitized: it is a mix of + + * http://www.itscj.ipsj.or.jp/iso-ir/006.pdf (G) + * http://www.itscj.ipsj.or.jp/iso-ir/001.pdf (C0) + * DEL character (0x7F) + + It is just 7-bit ASCII. + + >>> IA5String().allowable_chars + frozenset(["NUL", ... "DEL"]) + """ __slots__ = () tag_default = tag_encode(22) encoding = "ascii" asn1_type_name = "IA5" + _allowable_chars = frozenset(b"".join( + six_unichr(c).encode("ascii") for c in six_xrange(128) + )) LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ") @@ -4999,11 +5017,27 @@ LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ") LEN_LEN_YYYYMMDDHHMMSSZ = len_encode(LEN_YYYYMMDDHHMMSSZ) -class VisibleString(CommonString): +class VisibleString(AllowableCharsMixin, CommonString): + """Visible string + + Its value is properly sanitized. ASCII subset from space to tilde is + allowed: http://www.itscj.ipsj.or.jp/iso-ir/006.pdf + + >>> VisibleString().allowable_chars + frozenset([" ", ... "~"]) + """ __slots__ = () tag_default = tag_encode(26) encoding = "ascii" asn1_type_name = "VisibleString" + _allowable_chars = frozenset(b"".join( + six_unichr(c).encode("ascii") for c in six_xrange(ord(" "), ord("~") + 1) + )) + + +class ISO646String(VisibleString): + __slots__ = () + asn1_type_name = "ISO646String" UTCTimeState = namedtuple( @@ -5423,11 +5457,6 @@ class GraphicString(CommonString): asn1_type_name = "GraphicString" -class ISO646String(VisibleString): - __slots__ = () - asn1_type_name = "ISO646String" - - class GeneralString(CommonString): __slots__ = () tag_default = tag_encode(27) @@ -5845,7 +5874,7 @@ class Any(Obj): def _value_sanitize(self, value): if value.__class__ == binary_type: if len(value) == 0: - raise ValueError("Any value can not be empty") + raise ValueError("%s value can not be empty" % self.__class__.__name__) return value if isinstance(value, self.__class__): return value._value @@ -7413,7 +7442,7 @@ def ascii_visualize(ba): 92 2b 39 20 65 91 e6 8e 95 93 1a 58 df 02 78 ea |.+9 e......X..x.| ^^^^^^^^^^^^^^^^ """ - return "".join((chr(b) if 0x20 <= b <= 0x7E else ".") for b in ba) + return "".join((six_unichr(b) if 0x20 <= b <= 0x7E else ".") for b in ba) def hexdump(raw): @@ -7486,6 +7515,8 @@ def browse(raw, obj, oid_maps=()): If you press **d**, then current element will be saved in the current directory under its decode path name (adding ".0", ".1", etc suffix if such file already exists). **D** will save it with explicit tag. + + You can also invoke it with ``--browse`` command line argument. """ from copy import deepcopy from os.path import exists as path_exists @@ -7537,6 +7568,9 @@ def browse(raw, obj, oid_maps=()): [("header", "[TLV]len: "), "%d/%d/%d" % ( pp.tlen, pp.llen, pp.vlen, )], + [("header", "TLVlen: "), "%d" % sum(( + pp.tlen, pp.llen, pp.vlen, + ))], [("header", "Slice: "), "[%d:%d]" % ( pp.offset, pp.offset + pp.tlen + pp.llen + pp.vlen, )], @@ -7556,6 +7590,9 @@ def browse(raw, obj, oid_maps=()): lines.append([" [TLV]len: %d/%d/%d" % ( pp.expl_tlen, pp.expl_llen, pp.expl_vlen, )]) + lines.append([" TLVlen: %d" % sum(( + pp.expl_tlen, pp.expl_llen, pp.expl_vlen, + ))]) lines.append([" Slice: [%d:%d]" % ( pp.expl_offset, pp.expl_offset + pp.expl_tlen + pp.expl_llen + pp.expl_vlen,