Package paramiko :: Module ber |
[frames] | no frames]

# Source Code for Module paramiko.ber

      1  # Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com>
      2  #
      3  # This file is part of paramiko.
      4  #
      5  # Paramiko is free software; you can redistribute it and/or modify it under the
      6  # terms of the GNU Lesser General Public License as published by the Free
      7  # Software Foundation; either version 2.1 of the License, or (at your option)
      8  # any later version.
      9  #
     10  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY
     11  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     12  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
     13  # details.
     14  #
     15  # You should have received a copy of the GNU Lesser General Public License
     16  # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
     17  # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
     18
     19
     20  import util
     21
     22
     23 -class BERException (Exception):
     24      pass
     25
     26
     27 -class BER(object):
     28      """
     29      Robey's tiny little attempt at a BER decoder.
     30      """
     31
     32 -    def __init__(self, content=''):
     33          self.content = content
     34          self.idx = 0
     35
     36 -    def __str__(self):
     37          return self.content
     38
     39 -    def __repr__(self):
     40          return 'BER(\'' + repr(self.content) + '\')'
     41
     42 -    def decode(self):
     43          return self.decode_next()
     44
     45 -    def decode_next(self):
     46          if self.idx >= len(self.content):
     47              return None
     48          ident = ord(self.content[self.idx])
     49          self.idx += 1
     50          if (ident & 31) == 31:
     51              # identifier > 30
     52              ident = 0
     53              while self.idx < len(self.content):
     54                  t = ord(self.content[self.idx])
     55                  self.idx += 1
     56                  ident = (ident << 7) | (t & 0x7f)
     57                  if not (t & 0x80):
     58                      break
     59          if self.idx >= len(self.content):
     60              return None
     61          # now fetch length
     62          size = ord(self.content[self.idx])
     63          self.idx += 1
     64          if size & 0x80:
     65              # more complimicated...
     66              # FIXME: theoretically should handle indefinite-length (0x80)
     67              t = size & 0x7f
     68              if self.idx + t > len(self.content):
     69                  return None
     70              size = util.inflate_long(self.content[self.idx : self.idx + t], True)
     71              self.idx += t
     72          if self.idx + size > len(self.content):
     73              # can't fit
     74              return None
     75          data = self.content[self.idx : self.idx + size]
     76          self.idx += size
     77          # now switch on id
     78          if ident == 0x30:
     79              # sequence
     80              return self.decode_sequence(data)
     81          elif ident == 2:
     82              # int
     83              return util.inflate_long(data)
     84          else:
     85              # 1: boolean (00 false, otherwise true)
     86              raise BERException('Unknown ber encoding type %d (robey is lazy)' % ident)
     87
     88 -    def decode_sequence(data):
     89          out = []
     90          b = BER(data)
     91          while True:
     92              x = b.decode_next()
     93              if x is None:
     94                  break
     95              out.append(x)
     96          return out
     97      decode_sequence = staticmethod(decode_sequence)
     98
     99 -    def encode_tlv(self, ident, val):
    100          # no need to support ident > 31 here
    101          self.content += chr(ident)
    102          if len(val) > 0x7f:
    103              lenstr = util.deflate_long(len(val))
    104              self.content += chr(0x80 + len(lenstr)) + lenstr
    105          else:
    106              self.content += chr(len(val))
    107          self.content += val
    108
    109 -    def encode(self, x):
    110          if type(x) is bool:
    111              if x:
    112                  self.encode_tlv(1, '\xff')
    113              else:
    114                  self.encode_tlv(1, '\x00')
    115          elif (type(x) is int) or (type(x) is long):
    116              self.encode_tlv(2, util.deflate_long(x))
    117          elif type(x) is str:
    118              self.encode_tlv(4, x)
    119          elif (type(x) is list) or (type(x) is tuple):
    120              self.encode_tlv(0x30, self.encode_sequence(x))
    121          else:
    122              raise BERException('Unknown type for encoding: %s' % repr(type(x)))
    123
    124 -    def encode_sequence(data):
    125          b = BER()
    126          for item in data:
    127              b.encode(item)
    128          return str(b)
    129      encode_sequence = staticmethod(encode_sequence)
    130