Esempio n. 1
0
    def _parse_kexdh_reply(self, m):
        # The client runs this function.
        host_key = m.host_key

        server_f = self.dh.f = m.f

        if (server_f < 1) or (server_f > self.dh.P - 1):
            raise SshException('Server kex "f" is out of range')

        K = self.dh.calculate_k()

        if log.isEnabledFor(logging.DEBUG):
            log.debug("K=[{}].".format(K))

        # H = (V_C || V_S || I_C || I_S || K_S || e || f || K).
        hm = bytearray()
        hm += sshtype.encodeString(self.protocol.local_banner)
        hm += sshtype.encodeString(self.protocol.remote_banner)
        hm += sshtype.encodeBinary(self.protocol.local_kex_init_message)
        hm += sshtype.encodeBinary(self.protocol.remote_kex_init_message)
        hm += sshtype.encodeBinary(host_key)
        hm += sshtype.encodeMpint(self.dh.e)
        hm += sshtype.encodeMpint(server_f)
        hm += sshtype.encodeMpint(K)

        H = sha1(hm).digest()

        self.protocol.set_K_H(K, H)

        log.info("Verifying signature...")
        r = yield from self.protocol.verify_server_key(host_key, m.signature)
        return r
Esempio n. 2
0
    def verify_server_key(self, key_data, sig):
        if self.server_key:
            if self.server_key.asbytes() != key_data:
                raise SshException("Key provided by server differs from that"\
                    " which we were expecting (address=[{}])."\
                        .format(self.address))
        else:
            self.server_key = rsakey.RsaKey(key_data)

        if not self.server_key.verify_ssh_sig(self.h, sig):
            raise SshException("Signature verification failed (address=[{}])."\
                .format(self.address))

        log.info("Signature validated correctly!")

        r = yield from self.connection_handler.peer_authenticated(self)

        return r
Esempio n. 3
0
    def _process_encrypted_buffer(self):
        blksize = 16

        if self.inCipher != None:
#            if len(self.buf) > 20: # max(blksize, 20): bs, hmacSize
            if len(self.buf) < blksize:
                return False

            if len(self.cbuf) == 0:
                out = self.inCipher.decrypt(self.buf[:blksize])
                if log.isEnabledFor(logging.DEBUG):
                    log.debug("Decrypted [\n{}] to [\n{}]."\
                        .format(hex_dump(self.buf[:blksize]), hex_dump(out)))
                self.cbuf += out
                packet_length = struct.unpack(">L", out[:4])[0]
                log.debug("packet_length=[{}].".format(packet_length))
                if packet_length > MAX_PACKET_LENGTH:
                    errmsg = "Illegal packet_length [{}] received."\
                        .format(packet_length)
                    log.warning(errmsg)
                    raise SshException(errmsg)

                # Add size of packet_length as we leave it in buf.
                self.bpLength = packet_length + 4

                self.buf = self.buf[blksize:]

                if self.bpLength == blksize:
                    return True

            if len(self.buf) < min(\
                    1024, self.bpLength - len(self.cbuf) + self.inHmacSize):
                return True

            l = min(len(self.buf), self.bpLength - len(self.cbuf))
            if not l:
                return True

            dsize = l - (l % blksize)
            blks = self.buf[:dsize]
            self.buf = self.buf[dsize:]
            assert len(blks) % blksize == 0,\
                "len(blks)=[{}], dsize=[{}], l=[{}],"\
                " len(self.buf)=[{}], len(self.cbuf)=[{}], blksize=[{}],"\
                " self.bpLength=[{}], type(blks)=[{}]."\
                    .format(len(blks), dsize, l, len(self.buf),\
                        len(self.cbuf), blksize, self.bpLength, type(blks))
            out = self.inCipher.decrypt(blks)
            self.cbuf += out

            if log.isEnabledFor(logging.DEBUG):
                log.debug("Decrypted [\n{}] to [\n{}].".format(hex_dump(blks), hex_dump(out)))
                log.debug("len(cbuf)={}, cbuf=[\n{}]".format(len(self.cbuf), hex_dump(self.cbuf)))
        else:
            self.cbuf = self.buf

        return True
Esempio n. 4
0
    def read_packet(self, require_connected=True):
        if self.status is Status.disconnected:
            return None

        if require_connected and self.status is Status.closed:
            errstr = "ProtocolHandler closed, refusing read_packet(..)!"
            log.debug(errstr)
            raise SshException(errstr)

        if self.packet != None:
            packet = self.packet
            self.packet = None

            if packet[0] == 0x01:
                yield from\
                    self._peer_disconnected(\
                        mnetpacket.SshDisconnectMessage(packet))
                return None

            log.info("P: Returning next packet.")

            #asyncio.call_soon(self.process_buffer())
            # For now, call process_buffer in this event.
            if len(self.buf) > 0:
                self.process_buffer()

            return packet

        if self.status is Status.closed or self.status is Status.disconnected:
            return None

        log.info("P: Waiting for packet.")
        yield from self.do_wait()

        if self.status is Status.closed or self.status is Status.disconnected:
            return None

        assert self.packet != None
        packet = self.packet
        self.packet = None

        log.info("P: Notified of packet.")

        if packet[0] == 0x01:
            yield from\
                self._peer_disconnected(\
                    mnetpacket.SshDisconnectMessage(packet))
            return None

        # For now, call process_buffer in this event.
        if len(self.buf) > 0:
            self.process_buffer()

        return packet
Esempio n. 5
0
def connectTaskInsecure(protocol, server_mode):
    m = mnetpacket.SshKexdhReplyMessage()
    if server_mode:
        m.host_key = protocol.server_key.asbytes()
    else:
        m.host_key = protocol.client_key.asbytes()
    m.f = 42
    m.signature = b"test"
    m.encode()

    protocol.write_packet(m)

    pkt = yield from protocol.read_packet()
    if not pkt:
        return False

    m = mnetpacket.SshKexdhReplyMessage(pkt)

    if server_mode:
        if protocol.client_key:
            if protocol.client_key.asbytes() != m.host_key:
                raise SshException("Key provided by client differs from that which we were expecting.")
        else:
            protocol.client_key = rsakey.RsaKey(m.host_key)
    else:
        if protocol.server_key:
            if protocol.server_key.asbytes() != m.host_key:
                raise SshException("Key provided by server differs from that which we were expecting.")
        else:
            protocol.server_key = rsakey.RsaKey(m.host_key)

    r = yield from protocol.connection_handler.peer_authenticated(protocol)
    if not r:
        # Peer is rejected for some reason by higher level.
        protocol.close()
        return False

    return True
Esempio n. 6
0
    def _parse_kexdh_init(self, m):
        # The server runs this function.
        client_e = self.dh.f = m.e

        if (client_e < 1) or (client_e > self.dh.P - 1):
            raise SshException("Client kex 'e' is out of range")

        K = self.dh.calculate_k()

        if log.isEnabledFor(logging.DEBUG):
            log.debug("K=[{}].".format(K))

        key = self.protocol.server_key.asbytes()

        # H = (V_C || V_S || I_C || I_S || K_S || e || f || K).
        hm = bytearray()
        hm += sshtype.encodeString(self.protocol.remote_banner)
        hm += sshtype.encodeString(self.protocol.local_banner)
        hm += sshtype.encodeBinary(self.protocol.remote_kex_init_message)
        hm += sshtype.encodeBinary(self.protocol.local_kex_init_message)
        hm += sshtype.encodeBinary(key)
        hm += sshtype.encodeMpint(client_e)
        hm += sshtype.encodeMpint(self.dh.e)
        hm += sshtype.encodeMpint(K)

        H = sha1(hm).digest()

        self.protocol.set_K_H(K, H)

        # Sign it.
        sig = self.protocol.server_key.sign_ssh_data(H)

        # Send reply.
        m = mnp.SshKexdhReplyMessage()
        m.host_key = key
        m.f = self.dh.e
        m.signature = sig
        m.encode()

        self.protocol.write_packet(m)
Esempio n. 7
0
    def open_channel(self, channel_type, block=False):
        "Returns the channel queue for the new channel."

        if self.status is Status.new:
            if not block:
                raise SshException("Connection is not ready yet.")

            waiter = asyncio.futures.Future(loop=self.loop)
            self.ready_waiters.append(waiter)
            yield from waiter

        if self.status is not Status.ready:
            # Ignore if it is closed or disconnected.
            if log.isEnabledFor(logging.INFO):
                log.info("open_channel(..) called on a closed connection.")
            return None, None

        if self._implicit_channels_enabled:
            local_cid = self._open_implicit_channel(channel_type)
        else:
            local_cid = self._open_channel(channel_type)

        queue = self._create_channel_queue()
        self.channel_queues[local_cid] = queue

        if self._implicit_channels_enabled:
            yield from self.channel_handler.channel_opened(\
                self, None, local_cid, queue)
        elif block:
            r = yield from queue.get()
            if not r:
                # Could be None for disconnect or False for rejected.
                return local_cid, r
            assert r == True, "r=[{}]!".format(r)

        return local_cid, queue
Esempio n. 8
0
    def _process_buffer(self):
        if log.isEnabledFor(logging.DEBUG):
            log.debug("P: process_buffer(): called (binaryMode={}), buf=[\n{}].".format(self.binaryMode, hex_dump(self.buf)))

        assert self.binaryMode

        r = self._process_encrypted_buffer()
        if not r:
            return

        # cbuf is clear text buf.
        while True:
            if self.bpLength is None:
                assert not self.inCipher

                if len(self.cbuf) < 4:
                    return

                if log.isEnabledFor(logging.DEBUG):
                    log.debug("t=[{}].".format(self.cbuf[:4]))

                packet_length = struct.unpack(">L", self.cbuf[:4])[0]

                if log.isEnabledFor(logging.DEBUG):
                    log.debug("packet_length=[{}].".format(packet_length))

                if packet_length > MAX_PACKET_LENGTH:
                    errmsg = "Illegal packet_length [{}] received."\
                        .format(packet_length)
                    log.warning(errmsg)
                    raise SshException(errmsg)

                self.bpLength = packet_length + 4 # Add size of packet_length as we leave it in buf.
            else:
                if len(self.cbuf) < self.bpLength or len(self.buf) < self.inHmacSize:
                    return;

                if log.isEnabledFor(logging.DEBUG):
                    log.debug("PACKET READ (bpLength={}, inHmacSize={}, len(self.cbuf)={}, len(self.buf)={})".format(self.bpLength, self.inHmacSize, len(self.cbuf), len(self.buf)))

                padding_length = struct.unpack("B", self.cbuf[4:5])[0]
                log.debug("padding_length=[{}].".format(padding_length))

                padding_offset = self.bpLength - padding_length

                payload = self.cbuf[5:padding_offset]
                padding = self.cbuf[padding_offset:self.bpLength]
#                mac = self.cbuf[self.bpLength:self.bpLength + self.inHmacSize]
                mac = self.buf[:self.inHmacSize]

                if log.isEnabledFor(logging.DEBUG):
                    log.debug("payload=[\n{}], padding=[\n{}], mac=[\n{}] len(mac)={}.".format(hex_dump(payload), hex_dump(padding), hex_dump(mac), len(mac)))

                if self.inHmacSize != 0:
                    self.buf = self.buf[self.inHmacSize:]

                    mbuf = struct.pack(">L", self.inPacketId)
                    tmac = hmac.new(self.inHmacKey, digestmod=sha1)
                    tmac.update(mbuf)
                    tmac.update(self.cbuf)
                    cmac = tmac.digest()
                    if log.isEnabledFor(logging.DEBUG):
                        log.debug("inPacketId={} len(cmac)={}, cmac=[\n{}].".format(self.inPacketId, len(cmac), hex_dump(cmac)))
                    r = hmac.compare_digest(cmac, mac)
                    log.info("HMAC check result: [{}].".format(r))
                    if not r:
                        raise SshException("HMAC check failure, packetId={}.".format(self.inPacketId))

                newbuf = self.cbuf[self.bpLength + self.inHmacSize:]
                if self.cbuf == self.buf:
                    self.cbuf = bytearray()
                    self.buf = newbuf
                else:
                    self.cbuf = newbuf

                if self.waitingForNewKeys:
                    packet_type = mnetpacket.SshPacket.parse_type(payload)
                    if packet_type == mnetpacket.SSH_MSG_NEWKEYS:
                        if self.server_mode:
                            self.init_inbound_encryption()
                        else:
                            # Disable further processing until inbound
                            # encryption is setup. It may not have yet as
                            # parameters and newkeys may have come in same tcp
                            # packet.
                            self.set_inbound_enabled(False)
                        self.waitingForNewKeys = False

                self.packet = payload
                self.inPacketId = (self.inPacketId + 1) & 0xFFFFFFFF

                self.bpLength = None

                if self.waiter != None:
                    self.waiter.set_result(False)
                    self.waiter = None

                break;
Esempio n. 9
0
    def _process_ssh_packet(self, packet, offset=0):
        t = mnetpacket.SshPacket.parse_type(packet, offset)

        if log.isEnabledFor(logging.INFO):
            log.info("Received packet, type=[{}].".format(t))

        if t == mnetpacket.SSH_MSG_CHANNEL_OPEN:
            msg = mnetpacket.SshChannelOpenMessage(packet)
            if log.isEnabledFor(logging.INFO):
                log.info("P: Received CHANNEL_OPEN: channel_type=[{}],"\
                    " sender_channel=[{}]."\
                        .format(msg.channel_type, msg.sender_channel))

            if self._implicit_channels_enabled:
                if msg.data_packet is None:
                    raise SshException()

            if self._reverse_channel_map.get(msg.sender_channel):
                log.warning("Remote end sent a CHANNEL_OPEN request with an already open remote id; ignoring.")
                return

            r = yield from\
                self.channel_handler.request_open_channel(self, msg)

            if r:
                local_cid = self._accept_channel_open(msg)

                if log.isEnabledFor(logging.INFO):
                    log.info("Channel [{}] opened (address=[{}])."\
                        .format(local_cid, self.address))

                queue = self._create_channel_queue()
                self.channel_queues[local_cid] = queue

                yield from self.channel_handler.channel_opened(\
                    self, msg.channel_type, local_cid, queue)

                if self._implicit_channels_enabled:
                    yield from self._process_ssh_packet(msg.data_packet)
            elif not self._implicit_channels_enabled:
                self._open_channel_reject(msg)

        elif t == mnetpacket.SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
            if self._implicit_channels_enabled:
                raise SshException()
            msg = mnetpacket.SshChannelOpenConfirmationMessage(packet)
            log.info("P: Received CHANNEL_OPEN_CONFIRMATION:"\
                " sender_channel=[{}], recipient_channel=[{}]."\
                .format(msg.sender_channel, msg.recipient_channel))

            rcid = self._channel_map.get(msg.recipient_channel)
            if rcid == None:
                log.warning("Received a CHANNEL_OPEN_CONFIRMATION for a local channel that was not started; ignoring.")
                return
            if rcid == ChannelStatus.closing:
                log.warning("Received a CHANNEL_OPEN_CONFIRMATION for a local channel that was closed; ignoring.")
                return
            if rcid != ChannelStatus.opening:
                log.warning("Received a CHANNEL_OPEN_CONFIRMATION for a local channel that was already open; ignoring.")
                return

            lcid = self._reverse_channel_map\
                .setdefault(msg.sender_channel, msg.recipient_channel)

            if lcid is not msg.recipient_channel:
                log.warning("Received a CHANNEL_OPEN_CONFIRMATION for a remote channel that is already open; ignoring.")
                return

            self._channel_map[msg.recipient_channel] = msg.sender_channel

            if log.isEnabledFor(logging.INFO):
                log.info("Channel [{}] opened (address=[{}])."\
                    .format(msg.recipient_channel, self.address))

            # First 'packet' is a True, signaling the channel is open to
            # those yielding from the queue.
            queue = self.channel_queues[msg.recipient_channel]
            yield from queue.put(True)

            yield from self.channel_handler\
                .channel_opened(self, None, msg.recipient_channel, queue)

        elif t == mnetpacket.SSH_MSG_CHANNEL_OPEN_FAILURE:
            msg = mnetpacket.SshChannelOpenFailureMessage(packet)
            log.info("P: Received CHANNEL_OPEN_FAILURE recipient_channel=[{}].".format(msg.recipient_channel))

            queue = self.channel_queues[msg.recipient_channel]
            yield from queue.put(False)
            if (yield from self._close_channel(msg.recipient_channel, True)):
                yield from\
                    self.channel_handler.channel_open_failed(self, msg)

        elif t == mnetpacket.SSH_MSG_CHANNEL_IMPLICIT_WRAPPER:
            msg = mnetpacket.SshChannelImplicitWrapper(packet, offset)

            offset += mnetpacket.SshChannelImplicitWrapper.data_offset

            yield from self._process_ssh_packet(packet, offset)
        elif t == mnetpacket.SSH_MSG_CHANNEL_EXTENDED_DATA:
            raise SshException("Unimplemented.")
        elif t == mnetpacket.SSH_MSG_CHANNEL_DATA:
            msg = mnetpacket.SshChannelDataMessage(packet, offset)

            if offset:
                remote_cid = self._fix_implicit_msg(msg)
            else:
                remote_cid = self._channel_map[msg.recipient_channel]

            log.info("P: Received CHANNEL_DATA recipient_channel=[{}]."\
                .format(msg.recipient_channel))

            if remote_cid is None:
                raise SshException(\
                    "Received data for unmapped channel.")

            r = yield from self.channel_handler.channel_data(\
                self, msg.recipient_channel, msg.data)

            if not r:
                log.info(\
                    "Adding protocol (address={}) channel [{}] data"\
                    " to queue (remote_cid=[{}])."\
                    .format(self.address, msg.recipient_channel, remote_cid))
                yield from self.channel_queues[msg.recipient_channel]\
                    .put(msg.data)

        elif t == mnetpacket.SSH_MSG_CHANNEL_CLOSE:
            msg = mnetpacket.SshChannelCloseMessage(packet)

            if log.isEnabledFor(logging.INFO):
                log.info("P: Received CHANNEL_CLOSE (recipient_channel=[{}],"\
                    " implicit_channel=[{}])."\
                    .format(msg.recipient_channel, msg.implicit_channel))

            local_cid = msg.recipient_channel

            if self._implicit_channels_enabled:
                if msg.implicit_channel:
                    local_cid = self._reverse_channel_map[local_cid]
                    if log.isEnabledFor(logging.INFO):
                        log.info("implicit_channel, local_cid=[{}]."\
                            .format(local_cid))
            else:
                if msg.implicit_channel:
                    raise SshException()

            if (yield from self._close_channel(local_cid)):
                yield from self.channel_handler.channel_closed(\
                        self, local_cid)

        elif t == mnetpacket.SSH_MSG_CHANNEL_REQUEST:
            msg = mnetpacket.SshChannelRequest(packet, offset)

            if offset:
                self._fix_implicit_msg(msg)

            if log.isEnabledFor(logging.INFO):
                log.info("Received SSH_MSG_CHANNEL_REQUEST:"\
                " recipient_channel=[{}], request_type=[{}],"\
                " want_reply=[{}]."\
                    .format(msg.recipient_channel, msg.request_type,\
                        msg.want_reply))

            yield from self.channel_handler.channel_request(self, msg)
        else:
            log.warning("Unhandled packet of type [{}].".format(t))
Esempio n. 10
0
def connectTaskSecure(protocol, server_mode):
    # Send KexInit packet.
    opobj = mnetpacket.SshKexInitMessage()
    opobj.cookie = os.urandom(16)
#    opobj.kex_algorithms = "diffie-hellman-group-exchange-sha256"
    opobj.kex_algorithms = "diffie-hellman-group14-sha1"
    opobj.server_host_key_algorithms = "ssh-rsa"
    opobj.encryption_algorithms_client_to_server = "aes256-cbc"
    opobj.encryption_algorithms_server_to_client = "aes256-cbc"
#    opobj.mac_algorithms_client_to_server = "hmac-sha2-512"
#    opobj.mac_algorithms_server_to_client = "hmac-sha2-512"
    opobj.mac_algorithms_client_to_server = "hmac-sha1"
    opobj.mac_algorithms_server_to_client = "hmac-sha1"
    opobj.compression_algorithms_client_to_server = "none"
    opobj.compression_algorithms_server_to_client = "none"
    opobj.encode()

    protocol.local_kex_init_message = opobj.buf

    protocol.write_packet(opobj)

    # Read KexInit packet.
    packet = yield from protocol.read_packet()
    if not packet:
        return False

    if log.isEnabledFor(logging.DEBUG):
        log.debug("X: Received packet [{}].".format(hex_dump(packet)))

    packet_type = mnetpacket.SshPacket.parse_type(packet)

    if log.isEnabledFor(logging.INFO):
        log.info("packet_type=[{}].".format(packet_type))

    if packet_type != 20:
        log.warning("Peer sent unexpected packet_type[{}], disconnecting.".format(packet_type))
        protocol.close()
        return False

    protocol.remote_kex_init_message = packet

    pobj = mnetpacket.SshKexInitMessage(packet)
    if log.isEnabledFor(logging.DEBUG):
        log.debug("cookie=[{}].".format(pobj.cookie))
    if log.isEnabledFor(logging.INFO):
        log.info("keyExchangeAlgorithms=[{}].".format(pobj.kex_algorithms))

    protocol.waitingForNewKeys = True

#    ke = kex.KexGroup14(protocol)
#    log.info("Calling start_kex()...")
#    r = yield from ke.do_kex()
    ke = kexdhgroup14sha1.KexDhGroup14Sha1(protocol)
    log.info("Calling kex->run()...")
    r = yield from ke.run()

    if not r:
        # Client is rejected for some reason by higher level.
        protocol.close()
        return False

    # Setup encryption now that keys are exchanged.
    protocol.init_outbound_encryption()

    if not protocol.server_mode:
        """ Server gets done automatically since parameters are always there
            before NEWKEYS is received, but client the parameters and NEWKEYS
            message may come in the same tcppacket, so the auto part just turns
            off inbound processing and waits for us to call
            init_inbound_encryption when we have the parameters ready. """
        protocol.init_inbound_encryption()
        protocol.set_inbound_enabled(True)

    packet = yield from protocol.read_packet()
    if not packet:
        return False

    m = mnetpacket.SshNewKeysMessage(packet)
    log.debug("Received SSH_MSG_NEWKEYS.")

    if protocol.server_mode:
        packet = yield from protocol.read_packet()
        if not packet:
            return False

#        m = mnetpacket.SshPacket(None, packet)
#        log.info("X: Received packet (type={}) [{}].".format(m.packet_type, packet))
        m = mnetpacket.SshServiceRequestMessage(packet)
        log.info("Service requested [{}].".format(m.service_name))

        if m.service_name != "ssh-userauth":
            raise SshException("Remote end requested unexpected service (name=[{}]).".format(m.service_name))

        mr = mnetpacket.SshServiceAcceptMessage()
        mr.service_name = "ssh-userauth"
        mr.encode()

        protocol.write_packet(mr)

        packet = yield from protocol.read_packet()
        if not packet:
            return False

        m = mnetpacket.SshUserauthRequestMessage(packet)
        log.info("Userauth requested with method=[{}].".format(m.method_name))

        if m.method_name == "none":
            mr = mnetpacket.SshUserauthFailureMessage()
            mr.auths = "publickey"
            mr.partial_success = False
            mr.encode()

            protocol.write_packet(mr)

            packet = yield from protocol.read_packet()
            if not packet:
                return False

            m = mnetpacket.SshUserauthRequestMessage(packet)
            log.info("Userauth requested with method=[{}].".format(m.method_name))

        if m.method_name != "publickey":
            raise SshException("Unhandled client auth method [{}].".format(m.method_name))
        if m.algorithm_name != "ssh-rsa":
            raise SshException("Unhandled client auth algorithm [{}].".format(m.algorithm_name))

        log.debug("m.signature_present()={}.".format(m.signature_present))

        if not m.signature_present:
            mr = mnetpacket.SshUserauthPkOkMessage()
            mr.algorithm_name = m.algorithm_name
            mr.public_key = m.public_key
            mr.encode()

            protocol.write_packet(mr)

            packet = yield from protocol.read_packet()
            if not packet:
                return False

            m = mnetpacket.SshUserauthRequestMessage(packet)
            log.info("Userauth requested with method=[{}].".format(m.method_name))

            if m.method_name != "publickey":
                raise SshException("Unhandled client auth method [{}].".format(m.method_name))
            if m.algorithm_name != "ssh-rsa":
                raise SshException("Unhandled client auth algorithm [{}].".format(m.algorithm_name))

        if log.isEnabledFor(logging.DEBUG):
            log.debug("signature=[{}].".format(hex_dump(m.signature)))

        if protocol.client_key:
            if protocol.client_key.asbytes() != m.public_key:
                raise SshException("Key provided by client differs from that which we were expecting.")
        else:
            protocol.client_key = rsakey.RsaKey(m.public_key)

        buf = bytearray()
        buf += sshtype.encodeBinary(protocol.session_id)
        buf += packet[:-m.signature_length]

        r = protocol.client_key.verify_ssh_sig(buf, m.signature)

        log.info("Userauth signature check result: [{}].".format(r))
        if not r:
            raise SshException("Signature and key provided by client did not match.")

        r = yield from protocol.connection_handler.peer_authenticated(protocol)
        if not r:
            # Client is rejected for some reason by higher level.
            protocol.close()
            return False

        mr = mnetpacket.SshUserauthSuccessMessage()
        mr.encode()

        protocol.write_packet(mr)
    else:
        # client mode.
        m = mnetpacket.SshServiceRequestMessage()
        m.service_name = "ssh-userauth"
        m.encode()

        protocol.write_packet(m)

        packet = yield from protocol.read_packet()
        if not packet:
            return False

        m = mnetpacket.SshServiceAcceptMessage(packet)
        log.info("Service request accepted [{}].".format(m.service_name))

        mr = mnetpacket.SshUserauthRequestMessage()
        mr.user_name = "dev"
        mr.service_name = "ssh-connection"
        mr.method_name = "publickey"
        mr.signature_present = True
        mr.algorithm_name = "ssh-rsa"

        ckey = protocol.client_key
        mr.public_key = ckey.asbytes()

        mr.encode()

        mrb = bytearray()
        mrb += sshtype.encodeBinary(protocol.session_id)
        mrb += mr.buf

        sig = sshtype.encodeBinary(ckey.sign_ssh_data(mrb))

        mrb = mr.buf
        assert mr.buf == mrb
        mrb += sig

        protocol.write_packet(mr)

        packet = yield from protocol.read_packet()
        if not packet:
            return False

        m = mnetpacket.SshUserauthSuccessMessage(packet)
        log.info("Userauth accepted.")

    log.info("Connect task done (server={}).".format(server_mode))

#    if not server_mode:
#        protocol.close()

    return True