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_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(self, packet): MSG_KEX_DH_GEX_GROUP = 31 #We have to override this method since the original will #pick the client's ideal DH group size. For some SSH clients, this is #8192 bits, which takes minutes to compute. Instead, we pick the minimum, #which on our test client was 1024. if self.ignoreNextPacket: self.ignoreNextPacket = 0 return self.dhGexRequest = packet min, ideal, max = struct.unpack('>3L', packet) self.g, self.p = self.factory.getDHPrime(min) self.sendPacket(MSG_KEX_DH_GEX_GROUP, MP(self.p) + MP(self.g))
def ssh_KEX_DH_GEX_REQUEST(self, packet): """ Called when we receive a MSG_KEX_DH_GEX_REQUEST message. Payload:: integer minimum integer ideal integer maximum The client is asking for a Diffie-Hellman group between minimum and maximum size, and close to ideal if possible. We reply with a MSG_KEX_DH_GEX_GROUP message. If we were told to ignore the next key exchange packekt by ssh_KEXINIT, drop it on the floor and return. """ if self.ignoreNextPacket: self.ignoreNextPacket = 0 return self.dhGexRequest = packet min, ideal, max = struct.unpack('>3L', packet) self.g, self.p = self.factory.getDHPrime(ideal) self.sendPacket(MSG_KEX_DH_GEX_GROUP, MP(self.p) + MP(self.g))
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)