コード例 #1
0
ファイル: dsskey.py プロジェクト: zhangmh2/ssh
 def __init__(self,
              msg=None,
              data=None,
              filename=None,
              password=None,
              vals=None,
              file_obj=None):
     self.p = None
     self.q = None
     self.g = None
     self.y = None
     self.x = None
     if file_obj is not None:
         self._from_private_key(file_obj, password)
         return
     if filename is not None:
         self._from_private_key_file(filename, password)
         return
     if (msg is None) and (data is not None):
         msg = Message(data)
     if vals is not None:
         self.p, self.q, self.g, self.y = vals
     else:
         if msg is None:
             raise SSHException('Key object may not be empty')
         if msg.get_string() != 'ssh-dss':
             raise SSHException('Invalid key')
         self.p = msg.get_mpint()
         self.q = msg.get_mpint()
         self.g = msg.get_mpint()
         self.y = msg.get_mpint()
     self.size = util.bit_length(self.p)
コード例 #2
0
 def _read_private_key(self, tag, f, password=None):
     lines = f.readlines()
     start = 0
     while (start < len(lines)) and (lines[start].strip() != '-----BEGIN ' +
                                     tag + ' PRIVATE KEY-----'):
         start += 1
     if start >= len(lines):
         raise SSHException('not a valid ' + tag + ' private key file')
     # parse any headers first
     headers = {}
     start += 1
     while start < len(lines):
         l = lines[start].split(': ')
         if len(l) == 1:
             break
         headers[l[0].lower()] = l[1].strip()
         start += 1
     # find end
     end = start
     while (lines[end].strip() !=
            '-----END ' + tag + ' PRIVATE KEY-----') and (end < len(lines)):
         end += 1
     # if we trudged to the end of the file, just try to cope.
     try:
         data = base64.decodestring(''.join(lines[start:end]))
     except base64.binascii.Error, e:
         raise SSHException('base64 decoding error: ' + str(e))
コード例 #3
0
ファイル: dsskey.py プロジェクト: zhangmh2/ssh
 def _encode_key(self):
     if self.x is None:
         raise SSHException('Not enough key information')
     keylist = [0, self.p, self.q, self.g, self.y, self.x]
     try:
         b = BER()
         b.encode(keylist)
     except BERException:
         raise SSHException('Unable to create ber encoding of key')
     return str(b)
コード例 #4
0
 def _read_all(self, wanted):
     result = self.conn.recv(wanted)
     while len(result) < wanted:
         if len(result) == 0:
             raise SSHException('lost ssh-agent')
         extra = self.conn.recv(wanted - len(result))
         if len(extra) == 0:
             raise SSHException('lost ssh-agent')
         result += extra
     return result
コード例 #5
0
 def _encode_key(self):
     if (self.p is None) or (self.q is None):
         raise SSHException('Not enough key info to write private key file')
     keylist = [ 0, self.n, self.e, self.d, self.p, self.q,
                 self.d % (self.p - 1), self.d % (self.q - 1),
                 util.mod_inverse(self.q, self.p) ]
     try:
         b = BER()
         b.encode(keylist)
     except BERException:
         raise SSHException('Unable to create ber encoding of key')
     return str(b)
コード例 #6
0
 def _read_response(self, waitfor=None):
     while True:
         try:
             t, data = self._read_packet()
         except EOFError, e:
             raise SSHException('Server connection dropped: %s' %
                                (str(e), ))
         msg = Message(data)
         num = msg.get_int()
         if num not in self._expecting:
             # might be response for a file that was closed before responses came back
             self._log(DEBUG, 'Unexpected response #%d' % (num, ))
             if waitfor is None:
                 # just doing a single check
                 break
             continue
         fileobj = self._expecting[num]
         del self._expecting[num]
         if num == waitfor:
             # synchronous
             if t == CMD_STATUS:
                 self._convert_status(msg)
             return t, msg
         if fileobj is not type(None):
             fileobj._async_response(t, msg)
         if waitfor is None:
             # just doing a single check
             break
コード例 #7
0
 def _parse_kexdh_gex_reply(self, m):
     host_key = m.get_string()
     self.f = m.get_mpint()
     sig = m.get_string()
     if (self.f < 1) or (self.f > self.p - 1):
         raise SSHException('Server kex "f" is out of range')
     K = pow(self.f, self.x, self.p)
     # okay, build up the hash H of (V_C || V_S || I_C || I_S || K_S || min || n || max || p || g || e || f || K)
     hm = Message()
     hm.add(self.transport.local_version, self.transport.remote_version,
            self.transport.local_kex_init, self.transport.remote_kex_init,
            host_key)
     if not self.old_style:
         hm.add_int(self.min_bits)
     hm.add_int(self.preferred_bits)
     if not self.old_style:
         hm.add_int(self.max_bits)
     hm.add_mpint(self.p)
     hm.add_mpint(self.g)
     hm.add_mpint(self.e)
     hm.add_mpint(self.f)
     hm.add_mpint(K)
     self.transport._set_K_H(K, SHA.new(str(hm)).digest())
     self.transport._verify_key(host_key, sig)
     self.transport._activate_outbound()
コード例 #8
0
ファイル: dsskey.py プロジェクト: zhangmh2/ssh
 def _decode_key(self, data):
     # private key file contains:
     # DSAPrivateKey = { version = 0, p, q, g, y, x }
     try:
         keylist = BER(data).decode()
     except BERException, x:
         raise SSHException('Unable to parse key file: ' + str(x))
コード例 #9
0
 def _parse_kexdh_gex_request(self, m):
     minbits = m.get_int()
     preferredbits = m.get_int()
     maxbits = m.get_int()
     # smoosh the user's preferred size into our own limits
     if preferredbits > self.max_bits:
         preferredbits = self.max_bits
     if preferredbits < self.min_bits:
         preferredbits = self.min_bits
     # fix min/max if they're inconsistent.  technically, we could just pout
     # and hang up, but there's no harm in giving them the benefit of the
     # doubt and just picking a bitsize for them.
     if minbits > preferredbits:
         minbits = preferredbits
     if maxbits < preferredbits:
         maxbits = preferredbits
     # now save a copy
     self.min_bits = minbits
     self.preferred_bits = preferredbits
     self.max_bits = maxbits
     # generate prime
     pack = self.transport._get_modulus_pack()
     if pack is None:
         raise SSHException(
             'Can\'t do server-side gex with no modulus pack')
     self.transport._log(
         DEBUG, 'Picking p (%d <= %d <= %d bits)' %
         (minbits, preferredbits, maxbits))
     self.g, self.p = pack.get_modulus(minbits, preferredbits, maxbits)
     m = Message()
     m.add_byte(chr(_MSG_KEXDH_GEX_GROUP))
     m.add_mpint(self.p)
     m.add_mpint(self.g)
     self.transport._send_message(m)
     self.transport._expect_packet(_MSG_KEXDH_GEX_INIT)
コード例 #10
0
 def get_modulus(self, min, prefer, max):
     bitsizes = self.pack.keys()
     bitsizes.sort()
     if len(bitsizes) == 0:
         raise SSHException('no moduli available')
     good = -1
     # find nearest bitsize >= preferred
     for b in bitsizes:
         if (b >= prefer) and (b < max) and ((b < good) or (good == -1)):
             good = b
     # if that failed, find greatest bitsize >= min
     if good == -1:
         for b in bitsizes:
             if (b >= min) and (b < max) and (b > good):
                 good = b
     if good == -1:
         # their entire (min, max) range has no intersection with our range.
         # if their range is below ours, pick the smallest.  otherwise pick
         # the largest.  it'll be out of their range requirement either way,
         # but we'll be sending them the closest one we have.
         good = bitsizes[0]
         if min > good:
             good = bitsizes[-1]
     # now pick a random modulus of this bitsize
     n = _roll_random(self.rng, len(self.pack[good]))
     return self.pack[good][n]
コード例 #11
0
    def __init__(self, sock):
        """
        Create an SFTP client from an existing L{Channel}.  The channel
        should already have requested the C{"sftp"} subsystem.

        An alternate way to create an SFTP client context is by using
        L{from_transport}.

        @param sock: an open L{Channel} using the C{"sftp"} subsystem
        @type sock: L{Channel}

        @raise SSHException: if there's an exception while negotiating
            sftp
        """
        BaseSFTP.__init__(self)
        self.sock = sock
        self.ultra_debug = False
        self.request_number = 1
        # lock for request_number
        self._lock = threading.Lock()
        self._cwd = None
        # request # -> SFTPFile
        self._expecting = weakref.WeakValueDictionary()
        if type(sock) is Channel:
            # override default logger
            transport = self.sock.get_transport()
            self.logger = util.get_logger(transport.get_log_channel() +
                                          '.sftp')
            self.ultra_debug = transport.get_hexdump()
        try:
            server_version = self._send_version()
        except EOFError, x:
            raise SSHException('EOF during negotiation')
コード例 #12
0
 def _parse_kexdh_init(self, m):
     # server mode
     self.e = m.get_mpint()
     if (self.e < 1) or (self.e > P - 1):
         raise SSHException('Client kex "e" is out of range')
     K = pow(self.e, self.x, P)
     key = str(self.transport.get_server_key())
     # okay, build up the hash H of (V_C || V_S || I_C || I_S || K_S || e || f || K)
     hm = Message()
     hm.add(self.transport.remote_version, self.transport.local_version,
            self.transport.remote_kex_init, self.transport.local_kex_init)
     hm.add_string(key)
     hm.add_mpint(self.e)
     hm.add_mpint(self.f)
     hm.add_mpint(K)
     H = SHA.new(str(hm)).digest()
     self.transport._set_K_H(K, H)
     # sign it
     sig = self.transport.get_server_key().sign_ssh_data(self.transport.rng, H)
     # send reply
     m = Message()
     m.add_byte(chr(_MSG_KEXDH_REPLY))
     m.add_string(key)
     m.add_mpint(self.f)
     m.add_string(str(sig))
     self.transport._send_message(m)
     self.transport._activate_outbound()
コード例 #13
0
 def _decode_key(self, data):
     # private key file contains:
     # RSAPrivateKey = { version = 0, n, e, d, p, q, d mod p-1, d mod q-1, q**-1 mod p }
     try:
         keylist = BER(data).decode()
     except BERException:
         raise SSHException('Unable to parse key file')
     if (type(keylist) is not list) or (len(keylist) < 4) or (keylist[0] != 0):
         raise SSHException('Not a valid RSA private key file (bad ber encoding)')
     self.n = keylist[1]
     self.e = keylist[2]
     self.d = keylist[3]
     # not really needed
     self.p = keylist[4]
     self.q = keylist[5]
     self.size = util.bit_length(self.n)
コード例 #14
0
ファイル: auth_handler.py プロジェクト: zhangmh2/ssh
 def _parse_service_accept(self, m):
     service = m.get_string()
     if service == 'ssh-userauth':
         self.transport._log(DEBUG, 'userauth is OK')
         m = Message()
         m.add_byte(chr(MSG_USERAUTH_REQUEST))
         m.add_string(self.username)
         m.add_string('ssh-connection')
         m.add_string(self.auth_method)
         if self.auth_method == 'password':
             m.add_boolean(False)
             password = self.password
             if isinstance(password, unicode):
                 password = password.encode('UTF-8')
             m.add_string(password)
         elif self.auth_method == 'publickey':
             m.add_boolean(True)
             m.add_string(self.private_key.get_name())
             m.add_string(str(self.private_key))
             blob = self._get_session_blob(self.private_key,
                                           'ssh-connection', self.username)
             sig = self.private_key.sign_ssh_data(self.transport.rng, blob)
             m.add_string(str(sig))
         elif self.auth_method == 'keyboard-interactive':
             m.add_string('')
             m.add_string(self.submethods)
         elif self.auth_method == 'none':
             pass
         else:
             raise SSHException('Unknown auth method "%s"' %
                                self.auth_method)
         self.transport._send_message(m)
     else:
         self.transport._log(DEBUG,
                             'Service request "%s" accepted (?)' % service)
コード例 #15
0
    def resize_pty(self, width=80, height=24):
        """
        Resize the pseudo-terminal.  This can be used to change the width and
        height of the terminal emulation created in a previous L{get_pty} call.

        @param width: new width (in characters) of the terminal screen
        @type width: int
        @param height: new height (in characters) of the terminal screen
        @type height: int

        @raise SSHException: if the request was rejected or the channel was
            closed
        """
        if self.closed or self.eof_received or self.eof_sent or not self.active:
            raise SSHException('Channel is not open')
        m = Message()
        m.add_byte(chr(MSG_CHANNEL_REQUEST))
        m.add_int(self.remote_chanid)
        m.add_string('window-change')
        m.add_boolean(True)
        m.add_int(width)
        m.add_int(height)
        m.add_int(0).add_int(0)
        self._event_pending()
        self.transport._send_user_message(m)
        self._wait_for_event()
コード例 #16
0
    def invoke_subsystem(self, subsystem):
        """
        Request a subsystem on the server (for example, C{sftp}).  If the
        server allows it, the channel will then be directly connected to the
        requested subsystem.
        
        When the subsystem finishes, the channel will be closed and can't be
        reused.

        @param subsystem: name of the subsystem being requested.
        @type subsystem: str

        @raise SSHException: if the request was rejected or the channel was
            closed
        """
        if self.closed or self.eof_received or self.eof_sent or not self.active:
            raise SSHException('Channel is not open')
        m = Message()
        m.add_byte(chr(MSG_CHANNEL_REQUEST))
        m.add_int(self.remote_chanid)
        m.add_string('subsystem')
        m.add_boolean(True)
        m.add_string(subsystem)
        self._event_pending()
        self.transport._send_user_message(m)
        self._wait_for_event()
コード例 #17
0
    def exec_command(self, command):
        """
        Execute a command on the server.  If the server allows it, the channel
        will then be directly connected to the stdin, stdout, and stderr of
        the command being executed.
        
        When the command finishes executing, the channel will be closed and
        can't be reused.  You must open a new channel if you wish to execute
        another command.

        @param command: a shell command to execute.
        @type command: str

        @raise SSHException: if the request was rejected or the channel was
            closed
        """
        if self.closed or self.eof_received or self.eof_sent or not self.active:
            raise SSHException('Channel is not open')
        m = Message()
        m.add_byte(chr(MSG_CHANNEL_REQUEST))
        m.add_int(self.remote_chanid)
        m.add_string('exec')
        m.add_boolean(True)
        m.add_string(command)
        self._event_pending()
        self.transport._send_user_message(m)
        self._wait_for_event()
コード例 #18
0
 def invoke_shell(self):
     """
     Request an interactive shell session on this channel.  If the server
     allows it, the channel will then be directly connected to the stdin,
     stdout, and stderr of the shell.
     
     Normally you would call L{get_pty} before this, in which case the
     shell will operate through the pty, and the channel will be connected
     to the stdin and stdout of the pty.
     
     When the shell exits, the channel will be closed and can't be reused.
     You must open a new channel if you wish to open another shell.
     
     @raise SSHException: if the request was rejected or the channel was
         closed
     """
     if self.closed or self.eof_received or self.eof_sent or not self.active:
         raise SSHException('Channel is not open')
     m = Message()
     m.add_byte(chr(MSG_CHANNEL_REQUEST))
     m.add_int(self.remote_chanid)
     m.add_string('shell')
     m.add_boolean(1)
     self._event_pending()
     self.transport._send_user_message(m)
     self._wait_for_event()
コード例 #19
0
    def get_pty(self, term='vt100', width=80, height=24):
        """
        Request a pseudo-terminal from the server.  This is usually used right
        after creating a client channel, to ask the server to provide some
        basic terminal semantics for a shell invoked with L{invoke_shell}.
        It isn't necessary (or desirable) to call this method if you're going
        to exectue a single command with L{exec_command}.

        @param term: the terminal type to emulate (for example, C{'vt100'})
        @type term: str
        @param width: width (in characters) of the terminal screen
        @type width: int
        @param height: height (in characters) of the terminal screen
        @type height: int
        
        @raise SSHException: if the request was rejected or the channel was
            closed
        """
        if self.closed or self.eof_received or self.eof_sent or not self.active:
            raise SSHException('Channel is not open')
        m = Message()
        m.add_byte(chr(MSG_CHANNEL_REQUEST))
        m.add_int(self.remote_chanid)
        m.add_string('pty-req')
        m.add_boolean(True)
        m.add_string(term)
        m.add_int(width)
        m.add_int(height)
        # pixel height, width (usually useless)
        m.add_int(0).add_int(0)
        m.add_string('')
        self._event_pending()
        self.transport._send_user_message(m)
        self._wait_for_event()
コード例 #20
0
 def _wait_for_event(self):
     self.event.wait()
     assert self.event.isSet()
     if self.event_ready:
         return
     e = self.transport.get_exception()
     if e is None:
         e = SSHException('Channel closed.')
     raise e
コード例 #21
0
ファイル: agent.py プロジェクト: IHMEC/app-template
 def _connect(self, conn):
     self._conn = conn
     ptype, result = self._send_message(chr(SSH2_AGENTC_REQUEST_IDENTITIES))
     if ptype != SSH2_AGENT_IDENTITIES_ANSWER:
         raise SSHException('could not get keys from ssh-agent')
     keys = []
     for i in range(result.get_int()):
         keys.append(AgentKey(self, result.get_string()))
         result.get_string()
     self._keys = tuple(keys)
コード例 #22
0
 def sign_ssh_data(self, rng, data):
     msg = Message()
     msg.add_byte(chr(SSH2_AGENTC_SIGN_REQUEST))
     msg.add_string(self.blob)
     msg.add_string(data)
     msg.add_int(0)
     ptype, result = self.agent._send_message(msg)
     if ptype != SSH2_AGENT_SIGN_RESPONSE:
         raise SSHException('key cannot be used for signing')
     return result.get_string()
コード例 #23
0
 def parse_next(self, ptype, m):
     if ptype == _MSG_KEXDH_GEX_REQUEST:
         return self._parse_kexdh_gex_request(m)
     elif ptype == _MSG_KEXDH_GEX_GROUP:
         return self._parse_kexdh_gex_group(m)
     elif ptype == _MSG_KEXDH_GEX_INIT:
         return self._parse_kexdh_gex_init(m)
     elif ptype == _MSG_KEXDH_GEX_REPLY:
         return self._parse_kexdh_gex_reply(m)
     elif ptype == _MSG_KEXDH_GEX_REQUEST_OLD:
         return self._parse_kexdh_gex_request_old(m)
     raise SSHException('KexGex asked to handle packet type %d' % ptype)
コード例 #24
0
ファイル: auth_handler.py プロジェクト: zhangmh2/ssh
 def _parse_userauth_info_response(self, m):
     if not self.transport.server_mode:
         raise SSHException('Illegal info response from server')
     n = m.get_int()
     responses = []
     for i in range(n):
         responses.append(m.get_string())
     result = self.transport.server_object.check_auth_interactive_response(
         responses)
     if isinstance(type(result), InteractiveQuery):
         # make interactive query instead of response
         self._interactive_query(result)
         return
     self._send_auth_result(self.auth_username, 'keyboard-interactive',
                            result)
コード例 #25
0
 def _parse_kexdh_gex_group(self, m):
     self.p = m.get_mpint()
     self.g = m.get_mpint()
     # reject if p's bit length < 1024 or > 8192
     bitlen = util.bit_length(self.p)
     if (bitlen < 1024) or (bitlen > 8192):
         raise SSHException(
             'Server-generated gex p (don\'t ask) is out of range (%d bits)'
             % bitlen)
     self.transport._log(DEBUG, 'Got server p (%d bits)' % bitlen)
     self._generate_x()
     # now compute e = g^x mod p
     self.e = pow(self.g, self.x, self.p)
     m = Message()
     m.add_byte(chr(_MSG_KEXDH_GEX_INIT))
     m.add_mpint(self.e)
     self.transport._send_message(m)
     self.transport._expect_packet(_MSG_KEXDH_GEX_REPLY)
コード例 #26
0
 def _parse_kexdh_reply(self, m):
     # client mode
     host_key = m.get_string()
     self.f = m.get_mpint()
     if (self.f < 1) or (self.f > P - 1):
         raise SSHException('Server kex "f" is out of range')
     sig = m.get_string()
     K = pow(self.f, self.x, P)
     # okay, build up the hash H of (V_C || V_S || I_C || I_S || K_S || e || f || K)
     hm = Message()
     hm.add(self.transport.local_version, self.transport.remote_version,
            self.transport.local_kex_init, self.transport.remote_kex_init)
     hm.add_string(host_key)
     hm.add_mpint(self.e)
     hm.add_mpint(self.f)
     hm.add_mpint(K)
     self.transport._set_K_H(K, SHA.new(str(hm)).digest())
     self.transport._verify_key(host_key, sig)
     self.transport._activate_outbound()
コード例 #27
0
ファイル: auth_handler.py プロジェクト: zhangmh2/ssh
    def _parse_userauth_info_request(self, m):
        if self.auth_method != 'keyboard-interactive':
            raise SSHException('Illegal info request from server')
        title = m.get_string()
        instructions = m.get_string()
        m.get_string()  # lang
        prompts = m.get_int()
        prompt_list = []
        for i in range(prompts):
            prompt_list.append((m.get_string(), m.get_boolean()))
        response_list = self.interactive_handler(title, instructions,
                                                 prompt_list)

        m = Message()
        m.add_byte(chr(MSG_USERAUTH_INFO_RESPONSE))
        m.add_int(len(response_list))
        for r in response_list:
            m.add_string(r)
        self.transport._send_message(m)
コード例 #28
0
 def __init__(self):
     """
     Open a session with the local machine's SSH agent, if one is running.
     If no agent is running, initialization will succeed, but L{get_keys}
     will return an empty tuple.
     
     @raise SSHException: if an SSH agent is found, but speaks an
         incompatible protocol
     """
     self.conn = None
     self.keys = ()
     if ('SSH_AUTH_SOCK' in os.environ) and (sys.platform != 'win32'):
         conn = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
         try:
             conn.connect(os.environ['SSH_AUTH_SOCK'])
         except:
             # probably a dangling env var: the ssh agent is gone
             return
         self.conn = conn
     elif sys.platform == 'win32':
         import win_pageant
         if win_pageant.can_talk_to_agent():
             self.conn = win_pageant.PageantConnection()
         else:
             return
     else:
         # no agent support
         return
         
     ptype, result = self._send_message(chr(SSH2_AGENTC_REQUEST_IDENTITIES))
     if ptype != SSH2_AGENT_IDENTITIES_ANSWER:
         raise SSHException('could not get keys from ssh-agent')
     keys = []
     for i in range(result.get_int()):
         keys.append(AgentKey(self, result.get_string()))
         result.get_string()
     self.keys = tuple(keys)
コード例 #29
0
 def _parse_kexdh_gex_request_old(self, m):
     # same as above, but without min_bits or max_bits (used by older clients like putty)
     self.preferred_bits = m.get_int()
     # smoosh the user's preferred size into our own limits
     if self.preferred_bits > self.max_bits:
         self.preferred_bits = self.max_bits
     if self.preferred_bits < self.min_bits:
         self.preferred_bits = self.min_bits
     # generate prime
     pack = self.transport._get_modulus_pack()
     if pack is None:
         raise SSHException(
             'Can\'t do server-side gex with no modulus pack')
     self.transport._log(DEBUG,
                         'Picking p (~ %d bits)' % (self.preferred_bits, ))
     self.g, self.p = pack.get_modulus(self.min_bits, self.preferred_bits,
                                       self.max_bits)
     m = Message()
     m.add_byte(chr(_MSG_KEXDH_GEX_GROUP))
     m.add_mpint(self.p)
     m.add_mpint(self.g)
     self.transport._send_message(m)
     self.transport._expect_packet(_MSG_KEXDH_GEX_INIT)
     self.old_style = True
コード例 #30
0
 def _parse_kexdh_gex_init(self, m):
     self.e = m.get_mpint()
     if (self.e < 1) or (self.e > self.p - 1):
         raise SSHException('Client kex "e" is out of range')
     self._generate_x()
     self.f = pow(self.g, self.x, self.p)
     K = pow(self.e, self.x, self.p)
     key = str(self.transport.get_server_key())
     # okay, build up the hash H of (V_C || V_S || I_C || I_S || K_S || min || n || max || p || g || e || f || K)
     hm = Message()
     hm.add(self.transport.remote_version, self.transport.local_version,
            self.transport.remote_kex_init, self.transport.local_kex_init,
            key)
     if not self.old_style:
         hm.add_int(self.min_bits)
     hm.add_int(self.preferred_bits)
     if not self.old_style:
         hm.add_int(self.max_bits)
     hm.add_mpint(self.p)
     hm.add_mpint(self.g)
     hm.add_mpint(self.e)
     hm.add_mpint(self.f)
     hm.add_mpint(K)
     H = SHA.new(str(hm)).digest()
     self.transport._set_K_H(K, H)
     # sign it
     sig = self.transport.get_server_key().sign_ssh_data(
         self.transport.rng, H)
     # send reply
     m = Message()
     m.add_byte(chr(_MSG_KEXDH_GEX_REPLY))
     m.add_string(key)
     m.add_mpint(self.f)
     m.add_string(str(sig))
     self.transport._send_message(m)
     self.transport._activate_outbound()