def ssh_KEX_DH_GEX_REQUEST(self, packet): if self.ignoreNextPacket: self.ignoreNextPacket = 0 return self.min, self.ideal, self.max = struct.unpack('>3L', packet) self.g, self.p = self.factory.getDHPrime(self.ideal) self.sendPacket(MSG_KEX_DH_GEX_GROUP, MP(self.p) + MP(self.g))
def ssh_KEX_DH_GEX_REQUEST_OLD(self, packet): if self.ignoreNextPacket: self.ignoreNextPacket = 0 return if self.kexAlg == 'diffie-hellman-group1-sha1': # this is really KEXDH_INIT clientDHPubKey, foo = getMP(packet) y = Util.number.getRandomNumber(16, entropy.get_bytes) f = pow(DH_GENERATOR, y, DH_PRIME) sharedSecret = _MPpow(clientDHPubKey, y, DH_PRIME) h = sha.new() h.update(NS(self.otherVersionString)) h.update(NS(self.ourVersionString)) h.update(NS(self.clientKexInitPayload)) h.update(NS(self.ourKexInitPayload)) h.update(NS(self.factory.publicKeys[self.keyAlg])) h.update(MP(clientDHPubKey)) h.update(MP(f)) h.update(sharedSecret) exchangeHash = h.digest() self.sendPacket(MSG_KEXDH_REPLY, NS(self.factory.publicKeys[self.keyAlg])+ \ MP(f)+NS(keys.signData(self.factory.privateKeys[self.keyAlg], exchangeHash))) self._keySetup(sharedSecret, exchangeHash) elif self.kexAlg == 'diffie-hellman-group-exchange-sha1': self.kexAlg = 'diffie-hellman-group-exchange-sha1-old' self.ideal = struct.unpack('>L', packet)[0] self.g, self.p = self.factory.getDHPrime(self.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_INIT(self, packet): clientDHPubKey, foo = getMP(packet) # if y < 1024, openssh will reject us: "bad server public DH value". # y<1024 means f will be short, and of the form 2^y, so an observer # could trivially derive our secret y from f. Openssh detects this # and complains, so avoid creating such values by requiring y to be # larger than ln2(self.p) # 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 minimum = long(math.floor(math.log(self.p) / math.log(2)) + 1) tries = 0 pSize = Util.number.size(self.p) y = Util.number.getRandomNumber(pSize, entropy.get_bytes) while tries < 10 and y < minimum: tries += 1 y = Util.number.getRandomNumber(pSize, entropy.get_bytes) assert (y >= minimum) # TODO: test_conch just hangs if this is hit # the chance of it being hit are really really low f = pow(self.g, y, self.p) sharedSecret = _MPpow(clientDHPubKey, y, self.p) h = sha.new() h.update(NS(self.otherVersionString)) h.update(NS(self.ourVersionString)) h.update(NS(self.clientKexInitPayload)) h.update(NS(self.ourKexInitPayload)) h.update(NS(self.factory.publicKeys[self.keyAlg])) if self.kexAlg == 'diffie-hellman-group-exchange-sha1': h.update(struct.pack('>3L', self.min, self.ideal, self.max)) else: h.update(struct.pack('>L', self.ideal)) h.update(MP(self.p)) h.update(MP(self.g)) h.update(MP(clientDHPubKey)) h.update(MP(f)) h.update(sharedSecret) exchangeHash = h.digest() self.sendPacket(MSG_KEX_DH_GEX_REPLY, NS(self.factory.publicKeys[self.keyAlg])+ \ MP(f)+NS(keys.signData(self.factory.privateKeys[self.keyAlg], exchangeHash))) self._keySetup(sharedSecret, exchangeHash)
def _continueGEX_GROUP(self, ignored, pubKey, f, signature): serverKey = keys.getPublicKeyObject(pubKey) sharedSecret = _MPpow(f, self.x, DH_PRIME) h = sha.new() h.update(NS(self.ourVersionString)) h.update(NS(self.otherVersionString)) h.update(NS(self.ourKexInitPayload)) h.update(NS(self.serverKexInitPayload)) h.update(NS(pubKey)) h.update(MP(self.DHpubKey)) h.update(MP(f)) h.update(sharedSecret) exchangeHash = h.digest() if not keys.verifySignature(serverKey, signature, exchangeHash): self.sendDisconnect(DISCONNECT_KEY_EXCHANGE_FAILED, 'bad signature') return self._keySetup(sharedSecret, exchangeHash)
def ssh_KEX_DH_GEX_GROUP(self, packet): if self.kexAlg == 'diffie-hellman-group1-sha1': pubKey, packet = getNS(packet) f, packet = getMP(packet) signature, packet = getNS(packet) fingerprint = ':'.join(map(lambda c: '%02x'%ord(c), md5.new(pubKey).digest())) d = self.verifyHostKey(pubKey, fingerprint) d.addCallback(self._continueGEX_GROUP, pubKey, f, signature) d.addErrback(lambda unused,self=self:self.sendDisconnect(DISCONNECT_HOST_KEY_NOT_VERIFIABLE, 'bad host key')) else: self.p, rest = getMP(packet) self.g, rest = getMP(rest) self.x = getMP('\x00\x00\x00\x40'+entropy.get_bytes(64))[0] self.DHpubKey = pow(self.g, self.x, self.p) self.sendPacket(MSG_KEX_DH_GEX_INIT, MP(self.DHpubKey))
def ssh_KEXINIT(self, packet): self.serverKexInitPayload = chr(MSG_KEXINIT) + packet #cookie = packet[: 16] # taking this is unimportant k = getNS(packet[16:], 10) strings, rest = k[:-1], k[-1] kexAlgs, keyAlgs, encCS, encSC, macCS, macSC, compCS, compSC, langCS, langSC = \ [s.split(',')for s in strings] self.kexAlg = ffs(self.supportedKeyExchanges, kexAlgs) self.keyAlg = ffs(self.supportedPublicKeys, keyAlgs) self.nextEncryptions = SSHCiphers( ffs(self.supportedCiphers, encCS), ffs(self.supportedCiphers, encSC), ffs(self.supportedMACs, macCS), ffs(self.supportedMACs, macSC), ) self.outgoingCompressionType = ffs(self.supportedCompressions, compCS) self.incomingCompressionType = ffs(self.supportedCompressions, compSC) if None in (self.kexAlg, self.keyAlg, self.outgoingCompressionType, self.incomingCompressionType): self.sendDisconnect(DISCONNECT_KEY_EXCHANGE_FAILED, "couldn't match all kex parts") return if None in self.nextEncryptions.__dict__.values(): self.sendDisconnect(DISCONNECT_KEY_EXCHANGE_FAILED, "couldn't match all kex parts") return log.msg('kex alg, key alg: %s %s' % (self.kexAlg, self.keyAlg)) log.msg( 'client->server: %s %s %s' % (self.nextEncryptions.outCipType, self.nextEncryptions.outMacType, self.outgoingCompressionType)) log.msg('server->client: %s %s %s' % (self.nextEncryptions.inCipType, self.nextEncryptions.inMacType, self.incomingCompressionType)) if self.kexAlg == 'diffie-hellman-group1-sha1': self.x = Util.number.getRandomNumber(512, entropy.get_bytes) self.DHpubKey = pow(DH_GENERATOR, self.x, DH_PRIME) self.sendPacket(MSG_KEXDH_INIT, MP(self.DHpubKey)) else: self.sendPacket(MSG_KEX_DH_GEX_REQUEST_OLD, '\x00\x00\x08\x00')