1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 A Factory for SSH servers, along with an OpenSSHFactory to use the same
6 data sources as OpenSSH.
8 Maintainer: Paul Swartz
11 from twisted.internet import protocol
12 from twisted.python import log
13 from twisted.python.reflect import qual
15 from twisted.conch import error
16 from twisted.conch.ssh import keys
17 import transport, userauth, connection
22 class SSHFactory(protocol.Factory):
24 A Factory for SSH servers.
26 protocol = transport.SSHServerTransport
29 'ssh-userauth':userauth.SSHUserAuthServer,
30 'ssh-connection':connection.SSHConnection
32 def startFactory(self):
34 Check for public and private keys.
36 if not hasattr(self,'publicKeys'):
37 self.publicKeys = self.getPublicKeys()
38 for keyType, value in self.publicKeys.items():
39 if isinstance(value, str):
40 warnings.warn("Returning a mapping from strings to "
41 "strings from getPublicKeys()/publicKeys (in %s) "
42 "is deprecated. Return a mapping from "
43 "strings to Key objects instead." %
44 (qual(self.__class__)),
45 DeprecationWarning, stacklevel=1)
46 self.publicKeys[keyType] = keys.Key.fromString(value)
47 if not hasattr(self,'privateKeys'):
48 self.privateKeys = self.getPrivateKeys()
49 for keyType, value in self.privateKeys.items():
50 if not isinstance(value, keys.Key):
51 warnings.warn("Returning a mapping from strings to "
52 "PyCrypto key objects from "
53 "getPrivateKeys()/privateKeys (in %s) "
54 "is deprecated. Return a mapping from "
55 "strings to Key objects instead." %
56 (qual(self.__class__),),
57 DeprecationWarning, stacklevel=1)
58 self.privateKeys[keyType] = keys.Key(value)
59 if not self.publicKeys or not self.privateKeys:
60 raise error.ConchError('no host keys, failing')
61 if not hasattr(self,'primes'):
62 self.primes = self.getPrimes()
65 def buildProtocol(self, addr):
67 Create an instance of the server side of the SSH protocol.
69 @type addr: L{twisted.internet.interfaces.IAddress} provider
70 @param addr: The address at which the server will listen.
72 @rtype: L{twisted.conch.ssh.SSHServerTransport}
73 @return: The built transport.
75 t = protocol.Factory.buildProtocol(self, addr)
76 t.supportedPublicKeys = self.privateKeys.keys()
78 log.msg('disabling diffie-hellman-group-exchange because we '
79 'cannot find moduli file')
80 ske = t.supportedKeyExchanges[:]
81 ske.remove('diffie-hellman-group-exchange-sha1')
82 t.supportedKeyExchanges = ske
86 def getPublicKeys(self):
88 Called when the factory is started to get the public portions of the
89 servers host keys. Returns a dictionary mapping SSH key types to
94 raise NotImplementedError('getPublicKeys unimplemented')
97 def getPrivateKeys(self):
99 Called when the factory is started to get the private portions of the
100 servers host keys. Returns a dictionary mapping SSH key types to
101 C{Crypto.PublicKey.pubkey.pubkey} objects.
105 raise NotImplementedError('getPrivateKeys unimplemented')
110 Called when the factory is started to get Diffie-Hellman generators and
111 primes to use. Returns a dictionary mapping number of bits to lists
112 of tuple of (generator, prime).
118 def getDHPrime(self, bits):
120 Return a tuple of (g, p) for a Diffe-Hellman process, with p being as
121 close to bits bits as possible.
126 primesKeys = self.primes.keys()
127 primesKeys.sort(lambda x, y: cmp(abs(x - bits), abs(y - bits)))
128 realBits = primesKeys[0]
129 return random.choice(self.primes[realBits])
132 def getService(self, transport, service):
134 Return a class to use as a service for the given transport.
136 @type transport: L{transport.SSHServerTransport}
137 @type service: C{str}
138 @rtype: subclass of L{service.SSHService}
140 if service == 'ssh-userauth' or hasattr(transport, 'avatar'):
141 return self.services[service]