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)
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)
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)
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)
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)
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)
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")
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")
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)