def test_saveKeysha256(self): """ L{_saveKey} will generate key fingerprint in L{FingerprintFormats.SHA256-BASE64} format if explicitly specified. """ base = FilePath(self.mktemp()) base.makedirs() filename = base.child('id_rsa').path key = Key.fromString(privateRSA_openssh) _saveKey(key, {'filename': filename, 'pass': '******', 'format': 'sha256-base64'}) self.assertEqual( self.stdout.getvalue(), "Your identification has been saved in %s\n" "Your public key has been saved in %s.pub\n" "The key fingerprint in <FingerprintFormats=SHA256_BASE64> is:\n" "ryaugIFT0B8ItuszldMEU7q14rG/wj9HkRosMeBWkts=\n" % ( filename, filename)) self.assertEqual( key.fromString( base.child('id_rsa').getContent(), None, 'passphrase'), key) self.assertEqual( Key.fromString(base.child('id_rsa.pub').getContent()), key.public())
def manhole(username, password, globals): """Starts a ssh listener with password authentication using the given username and password. Clients connecting to the ssh listener will find themselves in a colored python shell with the supplied globals. Args: username(str): The username ssh clients should auth with. password(str): The password ssh clients should auth with. globals(dict): The variables to expose in the shell. Returns: twisted.internet.protocol.Factory: A factory to pass to ``listenTCP`` """ if not isinstance(password, bytes): password = password.encode('ascii') checker = checkers.InMemoryUsernamePasswordDatabaseDontUse( **{username: password} ) rlm = manhole_ssh.TerminalRealm() rlm.chainedProtocolFactory = lambda: insults.ServerProtocol( SynapseManhole, dict(globals, __name__="__console__") ) factory = manhole_ssh.ConchFactory(portal.Portal(rlm, [checker])) factory.publicKeys[b'ssh-rsa'] = Key.fromString(PUBLIC_KEY) factory.privateKeys[b'ssh-rsa'] = Key.fromString(PRIVATE_KEY) return factory
def verify_SSL_key_and_cert(keyfile, certfile): """ This function looks for RSA key and certificate in the current directory. If files ssl.key and ssl.cert does not exist, they are created. """ if not (os.path.exists(keyfile) and os.path.exists(certfile)): # key/cert does not exist. Create. import subprocess from Crypto.PublicKey import RSA from twisted.conch.ssh.keys import Key print(" Creating SSL key and certificate ... ", end=' ') try: # create the RSA key and store it. KEY_LENGTH = 1024 rsaKey = Key(RSA.generate(KEY_LENGTH)) keyString = rsaKey.toString(type="OPENSSH") file(keyfile, 'w+b').write(keyString) except Exception as err: print(NO_AUTOGEN.format(err=err, keyfile=keyfile)) sys.exit(5) # try to create the certificate CERT_EXPIRE = 365 * 20 # twenty years validity # default: # openssl req -new -x509 -key ssl.key -out ssl.cert -days 7300 exestring = "openssl req -new -x509 -key %s -out %s -days %s" % (keyfile, certfile, CERT_EXPIRE) try: subprocess.call(exestring) except OSError as err: raise OSError(NO_AUTOCERT.format(err=err, certfile=certfile, keyfile=keyfile, exestring=exestring)) print("done.")
def test_saveKey(self): """ L{_saveKey} writes the private and public parts of a key to two different files and writes a report of this to standard out. """ base = FilePath(self.mktemp()) base.makedirs() filename = base.child('id_rsa').path key = Key.fromString(privateRSA_openssh) _saveKey( key.keyObject, {'filename': filename, 'pass': '******'}) self.assertEqual( self.stdout.getvalue(), "Your identification has been saved in %s\n" "Your public key has been saved in %s.pub\n" "The key fingerprint is:\n" "3d:13:5f:cb:c9:79:8a:93:06:27:65:bc:3d:0b:8f:af\n" % ( filename, filename)) self.assertEqual( key.fromString( base.child('id_rsa').getContent(), None, 'passphrase'), key) self.assertEqual( Key.fromString(base.child('id_rsa.pub').getContent()), key.public())
def main(keys_path, username_get=None, gid=None, port=2022): settings.username_get = username_get settings.gid = gid key_path = keys_path + '/id_rsa' if not os.path.exists(key_path): subprocess.check_call(['ssh-keygen', '-f', key_path, '-t', 'rsa', '-N', '']) with open(key_path) as privateBlobFile: privateBlob = privateBlobFile.read() privateKey = Key.fromString(data=privateBlob) with open(key_path + '.pub') as publicBlobFile: publicBlob = publicBlobFile.read() publicKey = Key.fromString(data=publicBlob) factory = SSHFactory() factory.privateKeys = {'ssh-rsa': privateKey} factory.publicKeys = {'ssh-rsa': publicKey} factory.portal = Portal(KeyRealm()) factory.portal.registerChecker(KeyChecker()) reactor.listenTCP(port, factory) reactor.run()
def getKeyPair(pubkeyfile, privkeyfile): """ This function looks for RSA keypair files in the current directory. If they do not exist, the keypair is created. """ if not (os.path.exists(pubkeyfile) and os.path.exists(privkeyfile)): # No keypair exists. Generate a new RSA keypair from Crypto.PublicKey import RSA rsa_key = Key(RSA.generate(_KEY_LENGTH)) public_key_string = rsa_key.public().toString(type="OPENSSH") private_key_string = rsa_key.toString(type="OPENSSH") # save keys for the future. with open(privkeyfile, 'wt') as pfile: pfile.write(private_key_string) print("Created SSH private key in '{}'".format(_PRIVATE_KEY_FILE)) with open(pubkeyfile, 'wt') as pfile: pfile.write(public_key_string) print("Created SSH public key in '{}'".format(_PUBLIC_KEY_FILE)) else: with open(pubkeyfile) as pfile: public_key_string = pfile.read() with open(privkeyfile) as pfile: private_key_string = pfile.read() return Key.fromString(public_key_string), Key.fromString(private_key_string)
def _check_public_key (self, key, ) : try : Key.fromString(data=key, ) except BadKeyError : raise _exceptions.BAD_ARGUMENT("invalid public key.") return key.strip()
def test_savingsPreservesExisting(self): """ L{KnownHostsFile.save} will not overwrite existing entries in its save path, even if they were only added after the L{KnownHostsFile} instance was initialized. """ # Start off with one host/key pair in the file path = self.pathWithContent(sampleHashedLine) knownHosts = KnownHostsFile.fromPath(path) # After initializing the KnownHostsFile instance, add a second host/key # pair to the file directly - without the instance's help or knowledge. with path.open("a") as hostsFileObj: hostsFileObj.write(otherSamplePlaintextLine) # Add a third host/key pair using the KnownHostsFile instance key = Key.fromString(thirdSampleKey) knownHosts.addHostKey("brandnew.example.com", key) knownHosts.save() # Check that all three host/key pairs are present. knownHosts = KnownHostsFile.fromPath(path) self.assertEqual([True, True, True], [ knownHosts.hasHostKey( "www.twistedmatrix.com", Key.fromString(sampleKey)), knownHosts.hasHostKey( "divmod.com", Key.fromString(otherSampleKey)), knownHosts.hasHostKey("brandnew.example.com", key)])
def __init__(self, options): self.options = options # load private key with open(options['host-key']) as privateBlobFile: privateBlob = privateBlobFile.read() privateKey = Key.fromString(data=privateBlob) # load public key with open(options['host-key']+'.pub') as publicBlobFile: publicBlob = publicBlobFile.read() publicKey = Key.fromString(data=publicBlob) tickets = {} factory = AMPSSHFactory(tickets, self.options) factory.services['ssh-connection'] = SSHConnection # Load in keys the way SSHFactory expects them. factory.privateKeys = {'ssh-rsa': privateKey} factory.publicKeys = {'ssh-rsa': publicKey} # Give it a portal to authenticate clients with factory.portal = Portal(SimpleRealm(tickets, options, factory)) # validate against keys in authorized_keys files checker = AuthorizedKeys(options['authorized-keys']) factory.portal.registerChecker(checker) # init TCPServer with port and factory. internet.TCPServer.__init__(self, options['ssh-port'], factory) # remember for future reference self.factory = factory
def getKeyPair(pubkeyfile, privkeyfile): """ This function looks for RSA keypair files in the current directory. If they do not exist, the keypair is created. """ if not (os.path.exists(pubkeyfile) and os.path.exists(privkeyfile)): # No keypair exists. Generate a new RSA keypair print(" Generating SSH RSA keypair ...", end=' ') from Crypto.PublicKey import RSA KEY_LENGTH = 1024 rsaKey = Key(RSA.generate(KEY_LENGTH)) publicKeyString = rsaKey.public().toString(type="OPENSSH") privateKeyString = rsaKey.toString(type="OPENSSH") # save keys for the future. file(pubkeyfile, 'w+b').write(publicKeyString) file(privkeyfile, 'w+b').write(privateKeyString) print(" done.") else: publicKeyString = file(pubkeyfile).read() privateKeyString = file(privkeyfile).read() return Key.fromString(publicKeyString), Key.fromString(privateKeyString)
def test_saveKeyECDSA(self): """ L{_saveKey} writes the private and public parts of a key to two different files and writes a report of this to standard out. Test with ECDSA key. """ base = FilePath(self.mktemp()) base.makedirs() filename = base.child('id_ecdsa').path key = Key.fromString(privateECDSA_openssh) _saveKey(key, {'filename': filename, 'pass': '******', 'format': 'md5-hex'}) self.assertEqual( self.stdout.getvalue(), "Your identification has been saved in %s\n" "Your public key has been saved in %s.pub\n" "The key fingerprint in <FingerprintFormats=MD5_HEX> is:\n" "e2:3b:e8:1c:f8:c9:c7:de:8b:c0:00:68:2e:c9:2c:8a\n" % ( filename, filename)) self.assertEqual( key.fromString( base.child('id_ecdsa').getContent(), None, 'passphrase'), key) self.assertEqual( Key.fromString(base.child('id_ecdsa.pub').getContent()), key.public())
def addKeyFile(self, kfile, password=None): if not os.path.exists(kfile): raise Exception("Key file not found %s", kfile) try: self.keys.append(Key.fromFile(kfile)) except EncryptedKeyError: self.keys.append(Key.fromFile(kfile, passphrase=password))
def makeFactory(self): """Create and start the factory that our SSH server uses.""" factory = Factory( get_portal(None, None), private_key=Key.fromFile( get_key_path(PRIVATE_KEY_FILE)), public_key=Key.fromFile( get_key_path(PUBLIC_KEY_FILE))) factory.startFactory() return factory
def __init__(self, settings): self.settings = settings self.portal = Portal(Realm(settings)) self.portal.registerChecker(Checker(settings)) self.privateKeys = { 'ssh-rsa': Key.fromFile(settings['hadoukngit']['private_key']), } self.publicKeys = { 'ssh-rsa': Key.fromFile(settings['hadoukngit']['public_key']), }
def __init__(self, settings): self.settings = settings self.portal = Portal(OpenRukoRealm(settings)) self.portal.registerChecker(OpenRukoCredentialChecker(settings)) self.privateKeys = { 'ssh-rsa': Key.fromFile(settings['gitmouth_private_key']), } self.publicKeys = { 'ssh-rsa': Key.fromFile(settings['gitmouth_public_key']), }
def getRSAKeys(): print "running getRSAKeys" with open('/home/pi/.ssh/id_rsa') as privateBlobFile: privateBlob = privateBlobFile.read() privateKey = Key.fromString(data=privateBlob) with open('/home/pi/.ssh/id_rsa.pub') as publicBlobFile: publicBlob = publicBlobFile.read() publicKey = Key.fromString(data=publicBlob) return publicKey, privateKey
def test_notPresentKey(self): """ L{KnownHostsFile.hasHostKey} returns C{False} when a key for the given hostname is not present. """ hostsFile = self.loadSampleHostsFile() self.assertFalse(hostsFile.hasHostKey( b"non-existent.example.com", Key.fromString(sampleKey))) self.assertTrue(hostsFile.hasHostKey( b"www.twistedmatrix.com", Key.fromString(sampleKey))) self.assertFalse(hostsFile.hasHostKey( b"www.twistedmatrix.com", Key.fromString(ecdsaSampleKey)))
def test_verifyInvalidKey(self): """ Verifying an invalid key should return a L{Deferred} which fires with a L{HostKeyChanged} failure. """ hostsFile = self.loadSampleHostsFile() wrongKey = Key.fromString(thirdSampleKey) ui = FakeUI() hostsFile.addHostKey("1.2.3.4", Key.fromString(sampleKey)) d = hostsFile.verifyHostKey( ui, "www.twistedmatrix.com", "1.2.3.4", wrongKey) return self.assertFailure(d, HostKeyChanged)
def test_verifyValidKey(self): """ Verifying a valid key should return a L{Deferred} which fires with True. """ hostsFile = self.loadSampleHostsFile() hostsFile.addHostKey("1.2.3.4", Key.fromString(sampleKey)) ui = FakeUI() d = hostsFile.verifyHostKey(ui, "www.twistedmatrix.com", "1.2.3.4", Key.fromString(sampleKey)) l = [] d.addCallback(l.append) self.assertEqual(l, [True])
def test_matchesKey(self): """ L{IKnownHostEntry.matchesKey} checks to see if an entry matches a given SSH key. """ twistedmatrixDotCom = Key.fromString(sampleKey) divmodDotCom = Key.fromString(otherSampleKey) self.assertEqual( True, self.entry.matchesKey(twistedmatrixDotCom)) self.assertEqual( False, self.entry.matchesKey(divmodDotCom))
def test_equality(self): """ Two L{HashedEntry} instances compare equal if and only if they represent the same host and key in exactly the same way: the host salt, host hash, public key type, public key, and comment fields must all be equal. """ hostSalt = b"gJbSEPBG9ZSBoZpHNtZBD1bHKBA" hostHash = b"bQv+0Xa0dByrwkA1EB0E7Xop/Fo" publicKey = Key.fromString(sampleKey) keyType = networkString(publicKey.type()) comment = b"hello, world" entry = HashedEntry( hostSalt, hostHash, keyType, publicKey, comment) duplicate = HashedEntry( hostSalt, hostHash, keyType, publicKey, comment) # Vary the host salt self.assertNormalEqualityImplementation( entry, duplicate, HashedEntry( hostSalt[::-1], hostHash, keyType, publicKey, comment)) # Vary the host hash self.assertNormalEqualityImplementation( entry, duplicate, HashedEntry( hostSalt, hostHash[::-1], keyType, publicKey, comment)) # Vary the key type self.assertNormalEqualityImplementation( entry, duplicate, HashedEntry( hostSalt, hostHash, keyType[::-1], publicKey, comment)) # Vary the key self.assertNormalEqualityImplementation( entry, duplicate, HashedEntry( hostSalt, hostHash, keyType, Key.fromString(otherSampleKey), comment)) # Vary the comment self.assertNormalEqualityImplementation( entry, duplicate, HashedEntry( hostSalt, hostHash, keyType, publicKey, comment[::-1]))
def test_verifyInvalidKey(self): """ Verfying an invalid key should return a L{Deferred} which fires with a L{HostKeyChanged} failure. """ hostsFile = self.loadSampleHostsFile() wrongKey = Key.fromString(thirdSampleKey) ui = FakeUI() hostsFile.addHostKey("1.2.3.4", Key.fromString(sampleKey)) d = hostsFile.verifyHostKey( ui, "www.twistedmatrix.com", "1.2.3.4", wrongKey) l = [] d.addErrback(l.append) hkc = l[0].trap(HostKeyChanged)
def _testrun(self, keyType, keySize=None): filename = self.mktemp() if keySize is None: subprocess.call(['ckeygen', '-t', keyType, '-f', filename, '--no-passphrase']) else: subprocess.call(['ckeygen', '-t', keyType, '-f', filename, '--no-passphrase', '-b', keySize]) privKey = Key.fromFile(filename) pubKey = Key.fromFile(filename + '.pub') if keyType == 'ecdsa': self.assertEqual(privKey.type(), 'EC') else: self.assertEqual(privKey.type(), keyType.upper()) self.assertTrue(pubKey.isPublic())
def __init__(self, private_key_path, public_key_path, moduli_path=None, banner=None): portal = self._makePortal() ssh_factory = ParsnipSSHFactory( portal, private_key=Key.fromFile(private_key_path), public_key=Key.fromFile(public_key_path), banner=banner, moduli_path=moduli_path ) self.service = strports.service('tcp:22', ssh_factory)
def test_saveResetsClobberState(self): """ After L{KnownHostsFile.save} is used once with an instance initialized by the default initializer, contents of the save path are respected and preserved. """ hostsFile = KnownHostsFile(self.pathWithContent(sampleHashedLine)) preSave = hostsFile.addHostKey( "www.example.com", Key.fromString(otherSampleKey)) hostsFile.save() postSave = hostsFile.addHostKey( "another.example.com", Key.fromString(thirdSampleKey)) hostsFile.save() self.assertEqual([preSave, postSave], list(hostsFile.iterentries()))
def test_verifyHostIPMismatch(self): """ Verifying a key where the host is present (and correct), but the IP is present and different, should result the deferred firing in a HostKeyChanged failure. """ hostsFile = self.loadSampleHostsFile() rightKey = Key.fromString(sampleKey) wrongKey = Key.fromString(thirdSampleKey) ui = FakeUI() l = [] d = hostsFile.verifyHostKey( ui, "www.twistedmatrix.com", "4.3.2.1", wrongKey) d.addErrback(l.append) l[0].trap(HostKeyChanged)
def _load_key(filename): try: return Key.fromFile(filename) except EncryptedKeyError: for i in xrange(3): passphrase = getpass.getpass("passphrase for %s: " % (filename,)) if not passphrase: continue try: return Key.fromFile(filename, passphrase=passphrase) except BadKeyError: pass raise BadKeyPassphraseError()
def test_publicKeyAuthenticationFailure(self): """ If the SSH server rejects the key pair presented during authentication, the L{Deferred} returned by L{SSHCommandClientEndpoint.connect} fires with a L{Failure} wrapping L{AuthenticationFailed}. """ badKey = Key.fromString(privateRSA_openssh) self.setupKeyChecker(self.portal, {self.user: privateDSA_openssh}) endpoint = SSHCommandClientEndpoint.newConnection( self.reactor, b"/bin/ls -l", self.user, self.hostname, self.port, keys=[badKey], knownHosts=self.knownHosts, ui=FixedResponseUI(False)) factory = Factory() factory.protocol = Protocol connected = endpoint.connect(factory) server, client, pump = self.connectedServerAndClient( self.factory, self.reactor.tcpClients[0][2]) f = self.failureResultOf(connected) f.trap(AuthenticationFailed) # XXX Should assert something specific about the arguments of the # exception # Nothing useful can be done with the connection at this point, so the # endpoint should close it. self.assertTrue(client.transport.disconnecting)
def setUp(self): self.rsaPublic = Key.fromString(keydata.publicRSA_openssh) self.tmpdir = FilePath(self.mktemp()) self.tmpdir.makedirs() self.rsaFile = self.tmpdir.child('id_rsa') self.rsaFile.setContent(keydata.privateRSA_openssh) self.tmpdir.child('id_rsa.pub').setContent(keydata.publicRSA_openssh)
def test_mismatchedHostKey(self): """ If the SSH public key presented by the SSH server does not match the previously remembered key, as reported by the L{KnownHostsFile} instance use to construct the endpoint, for that server, the L{Deferred} returned by L{SSHCommandClientEndpoint.connect} fires with a L{Failure} wrapping L{HostKeyChanged}. """ differentKey = Key.fromString(privateDSA_openssh).public() knownHosts = KnownHostsFile(self.mktemp()) knownHosts.addHostKey(self.serverAddress.host, differentKey) knownHosts.addHostKey(self.hostname, differentKey) # The UI may answer true to any questions asked of it; they should # make no difference, since a *mismatched* key is not even optionally # allowed to complete a connection. ui = FixedResponseUI(True) endpoint = SSHCommandClientEndpoint.newConnection( self.reactor, b"/bin/ls -l", b"dummy user", self.hostname, self.port, password=b"dummy password", knownHosts=knownHosts, ui=ui) factory = Factory() factory.protocol = Protocol connected = endpoint.connect(factory) server, client, pump = self.connectedServerAndClient( self.factory, self.reactor.tcpClients[0][2]) f = self.failureResultOf(connected) f.trap(HostKeyChanged)
def _testrun(self, keyType, keySize=None, privateKeySubtype=None): filename = self.mktemp() args = ["ckeygen", "-t", keyType, "-f", filename, "--no-passphrase"] if keySize is not None: args.extend(["-b", keySize]) if privateKeySubtype is not None: args.extend(["--private-key-subtype", privateKeySubtype]) subprocess.call(args) privKey = Key.fromFile(filename) pubKey = Key.fromFile(filename + ".pub") if keyType == "ecdsa": self.assertEqual(privKey.type(), "EC") elif keyType == "ed25519": self.assertEqual(privKey.type(), "Ed25519") else: self.assertEqual(privKey.type(), keyType.upper()) self.assertTrue(pubKey.isPublic())
def getPublicKey(self): path = self.options['ssh-key'] # this works with rsa too # just change the name here and in getPrivateKey if not os.path.exists(path) or self.lastPublicKey: # the file doesn't exist, or we've tried a public key return return Key.fromFile(filename=path + '.pub')
def _testrun(self, keyType, keySize=None): filename = self.mktemp() if keySize is None: subprocess.call( ['ckeygen', '-t', keyType, '-f', filename, '--no-passphrase']) else: subprocess.call([ 'ckeygen', '-t', keyType, '-f', filename, '--no-passphrase', '-b', keySize ]) privKey = Key.fromFile(filename) pubKey = Key.fromFile(filename + '.pub') if keyType == 'ecdsa': self.assertEqual(privKey.type(), 'EC') else: self.assertEqual(privKey.type(), keyType.upper()) self.assertTrue(pubKey.isPublic())
def _generate(): """ Generate a new SSH key pair. """ privateKey = rsa.generate_private_key(public_exponent=65537, key_size=4096, backend=default_backend()) return Key(privateKey).toString('openssh')
def _testrun(self, keyType, keySize=None, privateKeySubtype=None): filename = self.mktemp() args = ['ckeygen', '-t', keyType, '-f', filename, '--no-passphrase'] if keySize is not None: args.extend(['-b', keySize]) if privateKeySubtype is not None: args.extend(['--private-key-subtype', privateKeySubtype]) subprocess.call(args) privKey = Key.fromFile(filename) pubKey = Key.fromFile(filename + '.pub') if keyType == 'ecdsa': self.assertEqual(privKey.type(), 'EC') elif keyType == 'ed25519': self.assertEqual(privKey.type(), 'Ed25519') else: self.assertEqual(privKey.type(), keyType.upper()) self.assertTrue(pubKey.isPublic())
def test_iterentriesUnsaved(self): """ If the save path for a L{KnownHostsFile} does not exist, L{KnownHostsFile.iterentries} still returns added but unsaved entries. """ hostsFile = KnownHostsFile(FilePath(self.mktemp())) hostsFile.addHostKey("www.example.com", Key.fromString(sampleKey)) self.assertEqual(1, len(list(hostsFile.iterentries())))
def test_unsavedEntryHasKeyMismatch(self): """ L{KnownHostsFile.hasHostKey} raises L{HostKeyChanged} if the host key is present in memory (but not yet saved), but different from the expected one. The resulting exception has a C{offendingEntry} indicating the given entry, but no filename or line number information (reflecting the fact that the entry exists only in memory). """ hostsFile = KnownHostsFile(FilePath(self.mktemp())) entry = hostsFile.addHostKey("www.example.com", Key.fromString(otherSampleKey)) exception = self.assertRaises(HostKeyChanged, hostsFile.hasHostKey, "www.example.com", Key.fromString(thirdSampleKey)) self.assertEqual(exception.offendingEntry, entry) self.assertEqual(exception.lineno, None) self.assertEqual(exception.path, None)
def test_verifyNonPresentKey_Yes(self): """ Verifying a key where neither the hostname nor the IP are present should result in the UI being prompted with a message explaining as much. If the UI says yes, the Deferred should fire with True. """ ui, l, knownHostsFile = self.verifyNonPresentKey() ui.promptDeferred.callback(True) self.assertEqual([True], l) reloaded = KnownHostsFile.fromPath(knownHostsFile.savePath) self.assertEqual( True, reloaded.hasHostKey("4.3.2.1", Key.fromString(thirdSampleKey))) self.assertEqual( True, reloaded.hasHostKey("sample-host.example.com", Key.fromString(thirdSampleKey)))
def test_hasNonPresentKey(self): """ L{KnownHostsFile.hasHostKey} returns C{False} when a key for the given hostname is not present. """ hostsFile = self.loadSampleHostsFile() self.assertEqual(False, hostsFile.hasHostKey( "non-existent.example.com", Key.fromString(sampleKey)))
def test_hasPresentKey(self): """ L{KnownHostsFile.hasHostKey} returns C{True} when a key for the given hostname is present and matches the expected key. """ hostsFile = self.loadSampleHostsFile() self.assertEqual(True, hostsFile.hasHostKey( "www.twistedmatrix.com", Key.fromString(sampleKey)))
def test_getHostKeyAlgorithms(self): """ For a given host, get the host key algorithms for that host in the known_hosts file. """ hostsFile = self.loadSampleHostsFile() hostsFile.addHostKey(b"www.twistedmatrix.com", Key.fromString(otherSampleKey)) hostsFile.addHostKey(b"www.twistedmatrix.com", Key.fromString(ecdsaSampleKey)) hostsFile.save() options = {} options["known-hosts"] = hostsFile.savePath.path algorithms = default.getHostKeyAlgorithms(b"www.twistedmatrix.com", options) expectedAlgorithms = [b"ssh-rsa", b"ecdsa-sha2-nistp256"] self.assertEqual(algorithms, expectedAlgorithms)
def test_equality(self): """ Two L{HashedEntry} instances compare equal if and only if they represent the same host and key in exactly the same way: the host salt, host hash, public key type, public key, and comment fields must all be equal. """ hostSalt = "gJbSEPBG9ZSBoZpHNtZBD1bHKBA" hostHash = "bQv+0Xa0dByrwkA1EB0E7Xop/Fo" publicKey = Key.fromString(sampleKey) comment = "hello, world" entry = HashedEntry(hostSalt, hostHash, publicKey.type(), publicKey, comment) duplicate = HashedEntry(hostSalt, hostHash, publicKey.type(), publicKey, comment) # Vary the host salt self.assertNormalEqualityImplementation( entry, duplicate, HashedEntry(hostSalt[::-1], hostHash, publicKey.type(), publicKey, comment)) # Vary the host hash self.assertNormalEqualityImplementation( entry, duplicate, HashedEntry(hostSalt, hostHash[::-1], publicKey.type(), publicKey, comment)) # Vary the key type self.assertNormalEqualityImplementation( entry, duplicate, HashedEntry(hostSalt, hostHash, publicKey.type()[::-1], publicKey, comment)) # Vary the key self.assertNormalEqualityImplementation( entry, duplicate, HashedEntry(hostSalt, hostHash, publicKey.type(), Key.fromString(otherSampleKey), comment)) # Vary the comment self.assertNormalEqualityImplementation( entry, duplicate, HashedEntry(hostSalt, hostHash, publicKey.type(), publicKey, comment[::-1]))
def check_keys(results): for key_data, comment in results: agent_key = Key.fromString(key_data, type='blob') Message.new(message_type="flocker.provision.ssh:agent_key", key_fingerprint=agent_key.fingerprint(), commnet=comment).write() if agent_key == key: return True raise KeyNotFound(expected_key=key)
def assertHostKey(self, shell, factory): """ Assert that the public and private keys provided by C{factory} match those specified by C{shell} and that they are L{Key} instances. """ privateKey = Key.fromString(shell.hostKey) self.assertEqual(factory.publicKeys, {'ssh-rsa': privateKey.public()}) self.assertEqual(factory.privateKeys, {'ssh-rsa': privateKey})
def validate_ssh_public_key(value): """Validate that the given value contains a valid SSH public key.""" try: key = Key.fromString(value) if not key.isPublic(): raise ValidationError( "Invalid SSH public key (this key is a private key).") except (BadKeyError, binascii.Error): raise ValidationError("Invalid SSH public key.")
def __repr__(self): """ Return a summarized representation of this item. """ fmt = "SecureShellConfiguration(storeID=%d, hostKeyFingerprint='%s')" privateKey = Key.fromString(data=self.hostKey) publicKeyBlob = privateKey.blob() fingerprint = md5(publicKeyBlob).hexdigest() return fmt % (self.storeID, fingerprint)
def verifyHostKey(self, pubKey, fingerprint): self._state = b'SECURING' hostname = self.factory.hostname ip = self.transport.getPeer().host d = self.knownHosts.verifyHostKey(self.factory.ui, hostname, ip, Key.fromString(pubKey)) d.addErrback(self._saveHostKeyFailure) return d
def test_key_not_regenerated(self): """ ``create_keypair`` does not generate a new key pair if one can already be found in ``id_rsa_flocker`` and ``id_rsa_flocker.pub``. """ ssh_config = FilePath(self.mktemp()) configurator = OpenSSHConfiguration(ssh_config_path=ssh_config, flocker_path=None) id_rsa = ssh_config.child(b"id_rsa_flocker") configurator.create_keypair() expected_key = Key.fromFile(id_rsa.path) configurator.create_keypair() self.assertEqual(expected_key, Key.fromFile(id_rsa.path))
def main(keys_path, port): with open(keys_path + '/id_rsa') as privateBlobFile: privateBlob = privateBlobFile.read() privateKey = Key.fromString(data=privateBlob) with open(keys_path + '/id_rsa.pub') as publicBlobFile: publicBlob = publicBlobFile.read() publicKey = Key.fromString(data=publicBlob) factory = SSHFactory() factory.privateKeys = {'ssh-rsa': privateKey} factory.publicKeys = {'ssh-rsa': publicKey} factory.portal = Portal(KeyRealm()) factory.portal.registerChecker(KeyChecker()) factory.portal.registerChecker(PasswordChecker()) reactor.listenTCP(port, factory) reactor.run()
def setUp(self): """ Patch 'open' in verifyHostKey. """ self.fakeFile = FakeFile() self.patch(default, "_open", self.patchedOpen) self.hostsOption = self.mktemp() knownHostsFile = KnownHostsFile(FilePath(self.hostsOption)) knownHostsFile.addHostKey("exists.example.com", Key.fromString(sampleKey)) knownHostsFile.addHostKey("4.3.2.1", Key.fromString(sampleKey)) knownHostsFile.save() self.fakeTransport = FakeObject() self.fakeTransport.factory = FakeObject() self.options = self.fakeTransport.factory.options = { 'host': "exists.example.com", 'known-hosts': self.hostsOption }
def __init__(self, portal, private_key_path, public_key_path, oops_configuration, main_log, access_log, access_log_path, strport='tcp:22', factory_decorator=None, banner=None): """Construct an SSH service. :param portal: The `twisted.cred.portal.Portal` that turns authentication requests into views on the system. :param private_key_path: The path to the SSH server's private key. :param public_key_path: The path to the SSH server's public key. :param oops_configuration: The section of the configuration file with the OOPS config details for this server. :param main_log: The name of the logger to log most of the server stuff to. :param access_log: The name of the logger object to log the server access details to. :param access_log_path: The path to the access log file. :param strport: The port to run the server on, expressed in Twisted's "strports" mini-language. Defaults to 'tcp:22'. :param factory_decorator: An optional callable that can decorate the server factory (e.g. with a `twisted.protocols.policies.TimeoutFactory`). It takes one argument, a factory, and must return a factory. :param banner: An announcement printed to users when they connect. By default, announce nothing. """ ssh_factory = Factory(portal, private_key=Key.fromFile(private_key_path), public_key=Key.fromFile(public_key_path), banner=banner) if factory_decorator is not None: ssh_factory = factory_decorator(ssh_factory) self.service = strports.service(strport, ssh_factory) self._oops_configuration = oops_configuration self._main_log = main_log self._access_log = access_log self._access_log_path = access_log_path
def test_inKnownHostsKeyChanged(self): """ L{default.isInKnownHosts} should return C{2} when a host with a key other than the given one is in the known hosts file. """ host = self.hashedEntries[b"4.3.2.1"].toString().split()[0] r = default.isInKnownHosts( host, Key.fromString(otherSampleKey).blob(), {"known-hosts": FilePath(self.hostsOption).path}) self.assertEqual(2, r)
def test_randomSalts(self): """ L{KnownHostsFile.addHostKey} generates a random salt for each new key, so subsequent salts will be different. """ hostsFile = self.loadSampleHostsFile() aKey = Key.fromString(thirdSampleKey) self.assertNotEqual( hostsFile.addHostKey("somewhere.example.com", aKey)._hostSalt, hostsFile.addHostKey("somewhere-else.example.com", aKey)._hostSalt)
def verify_SSL_key_and_cert(keyfile, certfile): """ This function looks for RSA key and certificate in the current directory. If files ssl.key and ssl.cert does not exist, they are created. """ if not (os.path.exists(keyfile) and os.path.exists(certfile)): # key/cert does not exist. Create. import subprocess from Crypto.PublicKey import RSA from twisted.conch.ssh.keys import Key print(" Creating SSL key and certificate ... ", end=" ") try: # create the RSA key and store it. KEY_LENGTH = 1024 rsaKey = Key(RSA.generate(KEY_LENGTH)) keyString = rsaKey.toString(type="OPENSSH") file(keyfile, "w+b").write(keyString) except Exception as err: print(NO_AUTOGEN.format(err=err, keyfile=keyfile)) sys.exit(5) # try to create the certificate CERT_EXPIRE = 365 * 20 # twenty years validity # default: # openssl req -new -x509 -key ssl.key -out ssl.cert -days 7300 exestring = "openssl req -new -x509 -key %s -out %s -days %s" % ( keyfile, certfile, CERT_EXPIRE, ) try: subprocess.call(exestring) except OSError as err: raise OSError( NO_AUTOCERT.format(err=err, certfile=certfile, keyfile=keyfile, exestring=exestring)) print("done.")
def test_savedEntryAfterAddHasKeyMismatch(self): """ Even after a new entry has been added in memory but not yet saved, the L{HostKeyChanged} exception raised by L{KnownHostsFile.hasHostKey} has a C{lineno} attribute which indicates the 1-based line number of the offending entry in the underlying file when the given host key does not match the expected host key. """ hostsFile = self.loadSampleHostsFile() hostsFile.addHostKey(b"www.example.com", Key.fromString(otherSampleKey)) exception = self.assertRaises( HostKeyChanged, hostsFile.hasHostKey, b"www.twistedmatrix.com", Key.fromString(otherSampleKey), ) self.assertEqual(exception.lineno, 1) self.assertEqual(exception.path, hostsFile.savePath)
def get_manhole_factory(namespace): """ Build a twisted manhole factory """ from twisted.conch import manhole, manhole_ssh from twisted.cred import portal, checkers # I really hate Twisted's default colors colors = { 'identifier': '\x1b[1;36m', 'keyword': '\x1b[33m', 'parameter': '\x1b[33m', 'variable': '\x1b[36m', 'string': '\x1b[35m', 'number': '\x1b[1;32m', 'op': '\x1b[33m' } manhole.VT102Writer.typeToColor.update(colors) realm = manhole_ssh.TerminalRealm() def get_manhole(_): return manhole.ColoredManhole(namespace) realm.chainedProtocolFactory.protocolFactory = get_manhole p = portal.Portal(realm) checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() checker.addUser(config.backdoor_user, config.backdoor_password) p.registerChecker(checker) factory = manhole_ssh.ConchFactory(p) # As of Twisted~v16.0.0 we now have to give host SSH keys to any subclass of SSHFactory key_path = os.path.expanduser(config.ssh_key_path) factory.publicKeys = { 'ssh-rsa': Key.fromFile(key_path) } factory.privateKeys = { 'ssh-rsa': Key.fromFile(key_path) } return factory
def test_displayPublicKeyEncrypted(self): """ L{displayPublicKey} prints out the public key associated with a given private key using the given passphrase when it's encrypted. """ filename = self.mktemp() pubKey = Key.fromString(publicRSA_openssh) FilePath(filename).setContent(privateRSA_openssh_encrypted) displayPublicKey({'filename': filename, 'pass': '******'}) self.assertEqual(self.stdout.getvalue().strip('\n'), pubKey.toString('openssh'))
def test_displayPublicKey(self): """ L{displayPublicKey} prints out the public key associated with a given private key. """ filename = self.mktemp() pubKey = Key.fromString(publicRSA_openssh) FilePath(filename).setContent(privateRSA_openssh) displayPublicKey({'filename': filename}) self.assertEqual(self.stdout.getvalue().strip('\n'), pubKey.toString('openssh'))
def manhole(settings: ManholeConfig, globals: Dict[str, Any]) -> Factory: """Starts a ssh listener with password authentication using the given username and password. Clients connecting to the ssh listener will find themselves in a colored python shell with the supplied globals. Args: username: The username ssh clients should auth with. password: The password ssh clients should auth with. globals: The variables to expose in the shell. Returns: A factory to pass to ``listenTCP`` """ username = settings.username password = settings.password.encode("ascii") priv_key = settings.priv_key if priv_key is None: priv_key = Key.fromString(PRIVATE_KEY) pub_key = settings.pub_key if pub_key is None: pub_key = Key.fromString(PUBLIC_KEY) checker = checkers.InMemoryUsernamePasswordDatabaseDontUse(**{username: password}) rlm = manhole_ssh.TerminalRealm() # mypy ignored here because: # - can't deduce types of lambdas # - variable is Type[ServerProtocol], expr is Callable[[], ServerProtocol] rlm.chainedProtocolFactory = lambda: insults.ServerProtocol( # type: ignore[misc,assignment] SynapseManhole, dict(globals, __name__="__console__") ) factory = manhole_ssh.ConchFactory(portal.Portal(rlm, [checker])) # conch has the wrong type on these dicts (says bytes to bytes, # should be bytes to Keys judging by how it's used). factory.privateKeys[b"ssh-rsa"] = priv_key # type: ignore[assignment] factory.publicKeys[b"ssh-rsa"] = pub_key # type: ignore[assignment] return factory
def test_fromString(self): """ Constructing a plain text entry from an unhashed known_hosts entry will result in an L{IKnownHostEntry} provider with 'keyString', 'hostname', and 'keyType' attributes. While outside the interface in question, these attributes are held in common by L{PlainEntry} and L{HashedEntry} implementations; other implementations should override this method in subclasses. """ entry = self.entry self.assertEqual(entry.publicKey, Key.fromString(sampleKey)) self.assertEqual(entry.keyType, "ssh-rsa")