Example #1
0
    def ssh_KEX_DH_GEX_REQUEST_OLD(self, packet):
        """
        This represents two different key exchange methods that share the
        same integer value.

        KEXDH_INIT (for diffie-hellman-group1-sha1 exchanges) payload::

                integer e (the client's Diffie-Hellman public key)

            We send the KEXDH_REPLY with our host key and signature.

        KEX_DH_GEX_REQUEST_OLD (for diffie-hellman-group-exchange-sha1)
        payload::

                integer ideal (ideal size for the Diffie-Hellman prime)

            We send the KEX_DH_GEX_GROUP message with the group that is
            closest in size to ideal.

        If we were told to ignore the next key exchange packet by
        ssh_KEXINIT, drop it on the floor and return.
        """
        if self.ignoreNextPacket:
            self.ignoreNextPacket = 0
            return
        if self.kexAlg == 'diffie-hellman-group1-sha1':
            # this is really KEXDH_INIT
            clientDHpublicKey, foo = getMP(packet)
            y = Util.number.getRandomNumber(512, randbytes.secureRandom)
            serverDHpublicKey = _MPpow(DH_GENERATOR, y, DH_PRIME)
            sharedSecret = _MPpow(clientDHpublicKey, y, DH_PRIME)
            h = sha1()
            h.update(NS(self.otherVersionString))
            h.update(NS(self.ourVersionString))
            h.update(NS(self.otherKexInitPayload))
            h.update(NS(self.ourKexInitPayload))
            h.update(NS(self.factory.publicKeys[self.keyAlg].blob()))
            h.update(MP(clientDHpublicKey))
            h.update(serverDHpublicKey)
            h.update(sharedSecret)
            exchangeHash = h.digest()
            self.sendPacket(
                MSG_KEXDH_REPLY,
                NS(self.factory.publicKeys[self.keyAlg].blob()) +
                serverDHpublicKey +
                NS(self.factory.privateKeys[self.keyAlg].sign(exchangeHash)))
            self._keySetup(sharedSecret, exchangeHash)
        elif self.kexAlg == 'diffie-hellman-group-exchange-sha1':
            self.dhGexRequest = packet
            ideal = struct.unpack('>L', packet)[0]
            self.g, self.p = self.factory.getDHPrime(ideal)
            self.sendPacket(MSG_KEX_DH_GEX_GROUP, MP(self.p) + MP(self.g))
        else:
            raise error.ConchError('bad kexalg: %s' % self.kexAlg)
Example #2
0
    def ssh_KEX_DH_GEX_REQUEST_OLD(self, packet):
        """
        This represents two different key exchange methods that share the
        same integer value.

        KEXDH_INIT (for diffie-hellman-group1-sha1 exchanges) payload::

                integer e (the client's Diffie-Hellman public key)

            We send the KEXDH_REPLY with our host key and signature.

        KEX_DH_GEX_REQUEST_OLD (for diffie-hellman-group-exchange-sha1)
        payload::

                integer ideal (ideal size for the Diffie-Hellman prime)

            We send the KEX_DH_GEX_GROUP message with the group that is
            closest in size to ideal.

        If we were told to ignore the next key exchange packet by
        ssh_KEXINIT, drop it on the floor and return.
        """
        if self.ignoreNextPacket:
            self.ignoreNextPacket = 0
            return
        if self.kexAlg == 'diffie-hellman-group1-sha1':
            # this is really KEXDH_INIT
            clientDHpublicKey, foo = getMP(packet)
            y = Util.number.getRandomNumber(512, randbytes.secureRandom)
            serverDHpublicKey = _MPpow(DH_GENERATOR, y, DH_PRIME)
            sharedSecret = _MPpow(clientDHpublicKey, y, DH_PRIME)
            h = sha.new()
            h.update(NS(self.otherVersionString))
            h.update(NS(self.ourVersionString))
            h.update(NS(self.otherKexInitPayload))
            h.update(NS(self.ourKexInitPayload))
            h.update(NS(self.factory.publicKeys[self.keyAlg].blob()))
            h.update(MP(clientDHpublicKey))
            h.update(serverDHpublicKey)
            h.update(sharedSecret)
            exchangeHash = h.digest()
            self.sendPacket(
                MSG_KEXDH_REPLY,
                NS(self.factory.publicKeys[self.keyAlg].blob()) +
                serverDHpublicKey +
                NS(self.factory.privateKeys[self.keyAlg].sign(exchangeHash)))
            self._keySetup(sharedSecret, exchangeHash)
        elif self.kexAlg == 'diffie-hellman-group-exchange-sha1':
            self.dhGexRequest = packet
            ideal = struct.unpack('>L', packet)[0]
            self.g, self.p = self.factory.getDHPrime(ideal)
            self.sendPacket(MSG_KEX_DH_GEX_GROUP, MP(self.p) + MP(self.g))
        else:
            raise error.ConchError('bad kexalg: %s' % self.kexAlg)
Example #3
0
    def _continueKEXDH_REPLY(self, ignored, pubKey, f, signature):
        """
        The host key has been verified, so we generate the keys.

        @param pubKey: the public key blob for the server's public key.
        @type pubKey: C{str}
        @param f: the server's Diffie-Hellman public key.
        @type f: C{long}
        @param signature: the server's signature, verifying that it has the
            correct private key.
        @type signature: C{str}
        """
        serverKey = keys.Key.fromString(pubKey)
        sharedSecret = _MPpow(f, self.x, DH_PRIME)
        if self.kexAlg == 'diffie-hellman-group-exchange-sha256':
            h = sha256()
        else:
            h = sha1()
        h.update(NS(self.ourVersionString))
        h.update(NS(self.otherVersionString))
        h.update(NS(self.ourKexInitPayload))
        h.update(NS(self.otherKexInitPayload))
        h.update(NS(pubKey))
        h.update(self.e)
        h.update(MP(f))
        h.update(sharedSecret)
        exchangeHash = h.digest()
        if not serverKey.verify(signature, exchangeHash):
            self.sendDisconnect(DISCONNECT_KEY_EXCHANGE_FAILED,
                                'bad signature')
            return
        self._keySetup(sharedSecret, exchangeHash)
Example #4
0
    def _continueGEX_REPLY(self, ignored, pubKey, f, signature):
        """
        The host key has been verified, so we generate the keys.

        @param pubKey: the public key blob for the server's public key.
        @type pubKey: C{str}
        @param f: the server's Diffie-Hellman public key.
        @type f: C{long}
        @param signature: the server's signature, verifying that it has the
            correct private key.
        @type signature: C{str}
        """
        serverKey = keys.Key.fromString(pubKey)
        sharedSecret = _MPpow(f, self.x, self.p)
        h = sha1()
        h.update(NS(self.ourVersionString))
        h.update(NS(self.otherVersionString))
        h.update(NS(self.ourKexInitPayload))
        h.update(NS(self.otherKexInitPayload))
        h.update(NS(pubKey))
        h.update('\x00\x00\x08\x00')
        h.update(MP(self.p))
        h.update(MP(self.g))
        h.update(self.e)
        h.update(MP(f))
        h.update(sharedSecret)
        exchangeHash = h.digest()
        if not serverKey.verify(signature, exchangeHash):
            self.sendDisconnect(DISCONNECT_KEY_EXCHANGE_FAILED,
                                'bad signature')
            return
        self._keySetup(sharedSecret, exchangeHash)
Example #5
0
    def ssh_KEX_DH_GEX_INIT(self, packet):
        """
        Called when we get a MSG_KEX_DH_GEX_INIT message.  Payload::
            integer e (client DH public key)

        We send the MSG_KEX_DH_GEX_REPLY message with our host key and
        signature.
        """
        clientDHpublicKey, foo = getMP(packet)
        # TODO: we should also look at the value they send to us and reject
        # insecure values of f (if g==2 and f has a single '1' bit while the
        # rest are '0's, then they must have used a small y also).

        # TODO: This could be computed when self.p is set up
        #  or do as openssh does and scan f for a single '1' bit instead

        pSize = Util.number.size(self.p)
        y = Util.number.getRandomNumber(pSize, randbytes.secureRandom)

        serverDHpublicKey = _MPpow(self.g, y, self.p)
        sharedSecret = _MPpow(clientDHpublicKey, y, self.p)
        h = sha1()
        h.update(NS(self.otherVersionString))
        h.update(NS(self.ourVersionString))
        h.update(NS(self.otherKexInitPayload))
        h.update(NS(self.ourKexInitPayload))
        h.update(NS(self.factory.publicKeys[self.keyAlg].blob()))
        h.update(self.dhGexRequest)
        h.update(MP(self.p))
        h.update(MP(self.g))
        h.update(MP(clientDHpublicKey))
        h.update(serverDHpublicKey)
        h.update(sharedSecret)
        exchangeHash = h.digest()
        self.sendPacket(
            MSG_KEX_DH_GEX_REPLY,
            NS(self.factory.publicKeys[self.keyAlg].blob()) +
            serverDHpublicKey +
            NS(self.factory.privateKeys[self.keyAlg].sign(exchangeHash)))
        self._keySetup(sharedSecret, exchangeHash)
Example #6
0
    def ssh_KEX_DH_GEX_INIT(self, packet):
        """
        Called when we get a MSG_KEX_DH_GEX_INIT message.  Payload::
            integer e (client DH public key)

        We send the MSG_KEX_DH_GEX_REPLY message with our host key and
        signature.
        """
        clientDHpublicKey, foo = getMP(packet)
        # TODO: we should also look at the value they send to us and reject
        # insecure values of f (if g==2 and f has a single '1' bit while the
        # rest are '0's, then they must have used a small y also).

        # TODO: This could be computed when self.p is set up
        #  or do as openssh does and scan f for a single '1' bit instead

        pSize = Util.number.size(self.p)
        y = Util.number.getRandomNumber(pSize, randbytes.secureRandom)

        serverDHpublicKey = _MPpow(self.g, y, self.p)
        sharedSecret = _MPpow(clientDHpublicKey, y, self.p)
        h = sha.new()
        h.update(NS(self.otherVersionString))
        h.update(NS(self.ourVersionString))
        h.update(NS(self.otherKexInitPayload))
        h.update(NS(self.ourKexInitPayload))
        h.update(NS(self.factory.publicKeys[self.keyAlg].blob()))
        h.update(self.dhGexRequest)
        h.update(MP(self.p))
        h.update(MP(self.g))
        h.update(MP(clientDHpublicKey))
        h.update(serverDHpublicKey)
        h.update(sharedSecret)
        exchangeHash = h.digest()
        self.sendPacket(
            MSG_KEX_DH_GEX_REPLY,
            NS(self.factory.publicKeys[self.keyAlg].blob()) +
            serverDHpublicKey +
            NS(self.factory.privateKeys[self.keyAlg].sign(exchangeHash)))
        self._keySetup(sharedSecret, exchangeHash)
Example #7
0
 def ssh_KEXINIT(self, packet):
     """
     Called when we receive a MSG_KEXINIT message.  For a description
     of the packet, see SSHTransportBase.ssh_KEXINIT().  Additionally,
     this method sends the first key exchange packet.  If the agreed-upon
     exchange is diffie-hellman-group1-sha1, generate a public key
     and send it in a MSG_KEXDH_INIT message.  If the exchange is
     diffie-hellman-group-exchange-sha1, ask for a 2048 bit group with a
     MSG_KEX_DH_GEX_REQUEST_OLD message.
     """
     if SSHTransportBase.ssh_KEXINIT(self, packet) is None:
         return  # we disconnected
     if self.kexAlg == 'diffie-hellman-group1-sha1':
         self.x = _generateX(randbytes.secureRandom, 512)
         self.e = _MPpow(DH_GENERATOR, self.x, DH_PRIME)
         self.sendPacket(MSG_KEXDH_INIT, self.e)
     elif self.kexAlg.startswith('diffie-hellman-group-exchange-'):
         self.sendPacket(MSG_KEX_DH_GEX_REQUEST_OLD, '\x00\x00\x08\x00')
     else:
         raise error.ConchError("somehow, the kexAlg has been set "
                                "to something we don't support")
Example #8
0
 def ssh_KEXINIT(self, packet):
     """
     Called when we receive a MSG_KEXINIT message.  For a description
     of the packet, see SSHTransportBase.ssh_KEXINIT().  Additionally,
     this method sends the first key exchange packet.  If the agreed-upon
     exchange is diffie-hellman-group1-sha1, generate a public key
     and send it in a MSG_KEXDH_INIT message.  If the exchange is
     diffie-hellman-group-exchange-sha1, ask for a 2048 bit group with a
     MSG_KEX_DH_GEX_REQUEST_OLD message.
     """
     if SSHTransportBase.ssh_KEXINIT(self, packet) is None:
         return  # we disconnected
     if self.kexAlg == 'diffie-hellman-group1-sha1':
         self.x = Util.number.getRandomNumber(512, randbytes.secureRandom)
         self.e = _MPpow(DH_GENERATOR, self.x, DH_PRIME)
         self.sendPacket(MSG_KEXDH_INIT, self.e)
     elif self.kexAlg == 'diffie-hellman-group-exchange-sha1':
         self.sendPacket(MSG_KEX_DH_GEX_REQUEST_OLD, '\x00\x00\x08\x00')
     else:
         raise error.ConchError("somehow, the kexAlg has been set "
                                "to something we don't support")
Example #9
0
    def ssh_KEX_DH_GEX_GROUP(self, packet):
        """
        This handles two different message which share an integer value.
        If the key exchange is diffie-hellman-group1-sha1, this is
        MSG_KEXDH_REPLY.  Payload::
            string serverHostKey
            integer f (server Diffie-Hellman public key)
            string signature

        We verify the host key by calling verifyHostKey, then continue in
        _continueKEXDH_REPLY.

        If the key exchange is diffie-hellman-group-exchange-sha1, this is
        MSG_KEX_DH_GEX_GROUP.  Payload::
            string g (group generator)
            string p (group prime)

        We generate a Diffie-Hellman public key and send it in a
        MSG_KEX_DH_GEX_INIT message.
        """
        if self.kexAlg == 'diffie-hellman-group1-sha1':
            # actually MSG_KEXDH_REPLY
            pubKey, packet = getNS(packet)
            f, packet = getMP(packet)
            signature, packet = getNS(packet)
            fingerprint = ':'.join([ch.encode('hex') for ch in
                                    md5.new(pubKey).digest()])
            d = self.verifyHostKey(pubKey, fingerprint)
            d.addCallback(self._continueKEXDH_REPLY, pubKey, f, signature)
            d.addErrback(
                lambda unused: self.sendDisconnect(
                    DISCONNECT_HOST_KEY_NOT_VERIFIABLE, 'bad host key'))
            return d
        else:
            self.p, rest = getMP(packet)
            self.g, rest = getMP(rest)
            self.x = Util.number.getRandomNumber(320, randbytes.secureRandom)
            self.e = _MPpow(self.g, self.x, self.p)
            self.sendPacket(MSG_KEX_DH_GEX_INIT, self.e)
Example #10
0
    def ssh_KEX_DH_GEX_GROUP(self, packet):
        """
        This handles two different message which share an integer value.
        If the key exchange is diffie-hellman-group1-sha1, this is
        MSG_KEXDH_REPLY.  Payload::
            string serverHostKey
            integer f (server Diffie-Hellman public key)
            string signature

        We verify the host key by calling verifyHostKey, then continue in
        _continueKEXDH_REPLY.

        If the key exchange is diffie-hellman-group-exchange-sha1, this is
        MSG_KEX_DH_GEX_GROUP.  Payload::
            string g (group generator)
            string p (group prime)

        We generate a Diffie-Hellman public key and send it in a
        MSG_KEX_DH_GEX_INIT message.
        """
        if self.kexAlg == 'diffie-hellman-group1-sha1':
            # actually MSG_KEXDH_REPLY
            pubKey, packet = getNS(packet)
            f, packet = getMP(packet)
            signature, packet = getNS(packet)
            fingerprint = ':'.join([ch.encode('hex') for ch in
                                    md5.new(pubKey).digest()])
            d = self.verifyHostKey(pubKey, fingerprint)
            d.addCallback(self._continueKEXDH_REPLY, pubKey, f, signature)
            d.addErrback(
                lambda unused: self.sendDisconnect(
                    DISCONNECT_HOST_KEY_NOT_VERIFIABLE, 'bad host key'))
            return d
        else:
            self.p, rest = getMP(packet)
            self.g, rest = getMP(rest)
            self.x = Util.number.getRandomNumber(320, randbytes.secureRandom)
            self.e = _MPpow(self.g, self.x, self.p)
            self.sendPacket(MSG_KEX_DH_GEX_INIT, self.e)