Beispiel #1
0
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 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())
Beispiel #3
0
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)
Beispiel #4
0
    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)])
Beispiel #6
0
 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 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 __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
Beispiel #9
0
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
Beispiel #10
0
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()
Beispiel #11
0
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_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_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_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_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_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 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)
Beispiel #20
0
def gce_provisioner(
    zone, project, ssh_public_key, gce_credentials=None
):
    """
    Create an :class:`IProvisioner` for provisioning nodes on GCE.

    :param unicode zone: The name of the zone in which to provision instances.
    :param unicode project: The name of the project in which to provision
        instances.
    :param unicode ssh_public_key: The public key that will be put on the VM
        for ssh access.
    :param dict gce_credentials: A dict that has the same content as the json
        blob generated by the GCE console when you add a key to a service
        account. The service account must have permissions to spin up VMs in
        the specified project.

    :return: An class:`IProvisioner` provider for GCE instances.
    """
    key = Key.fromString(bytes(ssh_public_key))
    credentials = gce_credentials_from_config(gce_credentials)
    compute = discovery.build('compute', 'v1', credentials=credentials)

    return GCEProvisioner(
        instance_builder=GCEInstanceBuilder(
            zone=unicode(zone),
            project=unicode(project),
            compute=compute,
        ),
        ssh_public_key=key,
    )
    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 requestAvatarId(self, credentials):
        key = Key.fromString(credentials.blob)
        fingerprint = key.fingerprint().replace(':', '')
        self.meta.fingerprint = fingerprint
        if (credentials.username == 'git'):
            # Todo, maybe verify the key with a process protocol call
            # (drush or http)
            def success():
                return credentials.username
            d = defer.maybeDeferred(success)
            d.addCallback(self.verify, credentials, key)
            return d
        else:
            """ If a user specified a non-git username, check that the user's key matches their username

            so that we can request a password if it does not."""
            service = Service(AuthProtocol('drupalorg-ssh-user-key'))
            service.request_bool({"username":credentials.username},
                                 {"fingerprint":fingerprint})
            def auth_callback(result):
                if result:
                    return credentials.username
                else:
                    return Failure(UnauthorizedLogin(credentials.username))
            service.addCallback(auth_callback)
            service.addCallback(self.verify, credentials, key)
            return service.deferred
 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(
         "www.example.com", Key.fromString(otherSampleKey))
     exception = self.assertRaises(
         HostKeyChanged, hostsFile.hasHostKey,
         "www.twistedmatrix.com", Key.fromString(otherSampleKey))
     self.assertEqual(exception.lineno, 1)
     self.assertEqual(exception.path, hostsFile.savePath)
 def checkKey(self, credentials):
     fingerprint = Key.fromString(credentials.blob).fingerprint()
     fingerprint = fingerprint.replace(':','')
     for k in self.meta.pubkeys(credentials.username):
         if k == fingerprint:
             return True
     return False
Beispiel #25
0
 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)
Beispiel #26
0
    def test_getPrivateKeyPassphrase(self):
        """
        L{SSHUserAuthClient} can get a private key from a file, and return a
        Deferred called back with a private L{Key} object, even if the key is
        encrypted.
        """
        rsaPrivate = Key.fromString(keydata.privateRSA_openssh)
        passphrase = 'this is the passphrase'
        self.rsaFile.setContent(rsaPrivate.toString('openssh', passphrase))
        options = ConchOptions()
        options.identitys = [self.rsaFile.path]
        client = SSHUserAuthClient("user",  options, None)
        # Populate the list of used files
        client.getPublicKey()

        def _getPassword(prompt):
            self.assertEqual(prompt,
                              "Enter passphrase for key '%s': " % (
                              self.rsaFile.path,))
            return passphrase

        def _cbGetPrivateKey(key):
            self.assertEqual(key.isPublic(), False)
            self.assertEqual(key, rsaPrivate)

        self.patch(client, '_getPassword', _getPassword)
        return client.getPrivateKey().addCallback(_cbGetPrivateKey)
    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)
Beispiel #28
0
def _extractCommon(string):
    """
    Extract common elements of base64 keys from an entry in a hosts file.

    @param string: A known hosts file entry (a single line).
    @type string: L{bytes}

    @return: a 4-tuple of hostname data (L{bytes}), ssh key type (L{bytes}), key
        (L{Key}), and comment (L{bytes} or L{None}).  The hostname data is
        simply the beginning of the line up to the first occurrence of
        whitespace.
    @rtype: L{tuple}
    """
    elements = string.split(None, 2)
    if len(elements) != 3:
        raise InvalidEntry()
    hostnames, keyType, keyAndComment = elements
    splitkey = keyAndComment.split(None, 1)
    if len(splitkey) == 2:
        keyString, comment = splitkey
        comment = comment.rstrip("\n")
    else:
        keyString = splitkey[0]
        comment = None
    key = Key.fromString(keyString.decode('base64'))
    return hostnames, keyType, key, comment
    def requestAvatarId(self, credentials):
        key = Key.fromString(credentials.blob)
        fingerprint = key.fingerprint().replace(':', '')
        self.meta.fingerprint = fingerprint
        if (credentials.username == 'git'):
            # Todo, maybe verify the key with a process protocol call
            # (drush or http)
            def success():
                return credentials.username
            d = defer.maybeDeferred(success)
            d.addCallback(self.verify, credentials, key)
            return d
        else:
            """ If a user specified a non-git username, check that the user's key matches their username

            so that we can request a password if it does not."""
            drush_process = drush.DrushProcessProtocolBool('drupalorg-ssh-user-key')
            drush_process.call(credentials.username, fingerprint)
            def username(self):
                if self.result:
                    return credentials.username
                else:
                    return Failure(UnauthorizedLogin(credentials.username))
            drush_process.deferred.addCallback(username)
            drush_process.deferred.addCallback(self.verify, credentials, key)
            return drush_process.deferred
    def verifyNonPresentKey(self):
        """
        Set up a test to verify a key that isn't present.  Return a 3-tuple of
        the UI, a list set up to collect the result of the verifyHostKey call,
        and the sample L{KnownHostsFile} being used.

        This utility method avoids returning a L{Deferred}, and records results
        in the returned list instead, because the events which get generated
        here are pre-recorded in the 'ui' object.  If the L{Deferred} in
        question does not fire, the it will fail quickly with an empty list.
        """
        hostsFile = self.loadSampleHostsFile()
        absentKey = Key.fromString(thirdSampleKey)
        ui = FakeUI()
        l = []
        d = hostsFile.verifyHostKey(
            ui, "sample-host.example.com", "4.3.2.1", absentKey)
        d.addBoth(l.append)
        self.assertEqual([], l)
        self.assertEqual(
            ui.promptText,
            "The authenticity of host 'sample-host.example.com (4.3.2.1)' "
            "can't be established.\n"
            "RSA key fingerprint is "
            "89:4e:cc:8c:57:83:96:48:ef:63:ad:ee:99:00:4c:8f.\n"
            "Are you sure you want to continue connecting (yes/no)? ")
        return ui, l, hostsFile
Beispiel #31
0
    def verifyHostKey(self, hostKey, fingerprint):
        """
        Ask the L{KnownHostsFile} provider available on the factory which
        created this protocol this protocol to verify the given host key.

        @return: A L{Deferred} which fires with the result of
            L{KnownHostsFile.verifyHostKey}.
        """
        hostname = self.creator.hostname
        ip = self.transport.getPeer().host

        self._state = b'SECURING'
        d = self.creator.knownHosts.verifyHostKey(self.creator.ui, hostname,
                                                  ip, Key.fromString(hostKey))
        d.addErrback(self._saveHostKeyFailure)
        return d
Beispiel #32
0
 def test_saveKeyEmptyPassphrase(self):
     """
     L{_saveKey} will choose an empty string for the passphrase if
     no-passphrase is C{True}.
     """
     base = FilePath(self.mktemp())
     base.makedirs()
     filename = base.child('id_rsa').path
     key = Key.fromString(privateRSA_openssh)
     _saveKey(
         key.keyObject,
         {'filename': filename, 'no-passphrase': True})
     self.assertEqual(
         key.fromString(
             base.child('id_rsa').getContent(), None, b''),
         key)
Beispiel #33
0
 def test_saveKeyECDSAEmptyPassphrase(self):
     """
     L{_saveKey} will choose an empty string for the passphrase if
     no-passphrase is C{True}.
     """
     base = FilePath(self.mktemp())
     base.makedirs()
     filename = base.child('id_ecdsa').path
     key = Key.fromString(privateECDSA_openssh)
     _saveKey(key, {
         'filename': filename,
         'no-passphrase': True,
         'format': 'md5-hex'
     })
     self.assertEqual(
         key.fromString(base.child('id_ecdsa').getContent(), None), key)
Beispiel #34
0
    def test_saveKeyNoFilename(self):
        """
        When no path is specified, it will ask for the path used to store the
        key.
        """
        base = FilePath(self.mktemp())
        base.makedirs()
        keyPath = base.child('custom_key').path

        self.patch(__builtin__, 'raw_input', lambda _: keyPath)
        key = Key.fromString(privateRSA_openssh)
        _saveKey(key, {'filename': None, 'no-passphrase': True})

        persistedKeyContent = base.child('custom_key').getContent()
        persistedKey = key.fromString(persistedKeyContent, None, b'')
        self.assertEqual(key, persistedKey)
Beispiel #35
0
 def test_displayPublicKeyEncryptedPassphrasePrompt(self):
     """
     L{displayPublicKey} prints out the public key associated with a given
     private key, asking for the passphrase when it's encrypted.
     """
     filename = self.mktemp()
     pubKey = Key.fromString(publicRSA_openssh)
     FilePath(filename).setContent(privateRSA_openssh_encrypted)
     self.patch(getpass, 'getpass', lambda x: 'encrypted')
     displayPublicKey({'filename': filename})
     displayed = self.stdout.getvalue().strip('\n')
     if isinstance(displayed, unicode):
         displayed = displayed.encode("ascii")
     self.assertEqual(
         displayed,
         pubKey.toString('openssh'))
 def test_saveKeyEd25519EmptyPassphrase(self):
     """
     L{_saveKey} will choose an empty string for the passphrase if
     no-passphrase is C{True}.
     """
     base = FilePath(self.mktemp())
     base.makedirs()
     filename = base.child("id_ed25519").path
     key = Key.fromString(privateEd25519_openssh_new)
     _saveKey(key, {
         "filename": filename,
         "no-passphrase": True,
         "format": "md5-hex"
     })
     self.assertEqual(
         key.fromString(base.child("id_ed25519").getContent(), None), key)
Beispiel #37
0
 def test_getPublicKeyBadKeyError(self):
     """
     If L{keys.Key.fromFile} raises a L{keys.BadKeyError}, the
     L{SSHUserAuthClient.getPublicKey} tries again to get a public key by
     calling itself recursively.
     """
     options = ConchOptions()
     self.tmpdir.child('id_dsa.pub').setContent(keydata.publicDSA_openssh)
     dsaFile = self.tmpdir.child('id_dsa')
     dsaFile.setContent(keydata.privateDSA_openssh)
     options.identitys = [self.rsaFile.path, dsaFile.path]
     self.tmpdir.child('id_rsa.pub').setContent('not a key!')
     client = SSHUserAuthClient("user",  options, None)
     key = client.getPublicKey()
     self.assertEqual(key.isPublic(), True)
     self.assertEqual(key, Key.fromString(keydata.publicDSA_openssh))
     self.assertEqual(client.usedFiles, [self.rsaFile.path, dsaFile.path])
Beispiel #38
0
    def get_ssh_key(self):
        """
        Return the public key associated with the provided keyname.

        :return Key: The ssh public key or ``None`` if it can't be determined.
        """
        try:
            key_pair = self._driver.get_key_pair(self._keyname)
        except Exception:
            raise CloudKeyNotFound(self._keyname)
        if key_pair.public_key is not None:
            return Key.fromString(key_pair.public_key, type='public_openssh')
        else:
            # EC2 only provides the SSH2 fingerprint (for uploaded keys)
            # or the SHA-1 hash of the private key (for EC2 generated keys)
            # https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_KeyPairInfo.html
            return None
    def test_authenticationFallback(self):
        """
        If the SSH server does not accept any of the specified SSH keys, the
        specified password is tried.
        """
        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],
            password=self.password,
            knownHosts=self.knownHosts,
            ui=FixedResponseUI(False))

        factory = Factory()
        factory.protocol = Protocol
        connected = endpoint.connect(factory)

        # Exercising fallback requires a failed authentication attempt.  Allow
        # one.
        self.factory.attemptsBeforeDisconnect += 1

        server, client, pump = self.connectedServerAndClient(
            self.factory, self.reactor.tcpClients[0][2])

        pump.pump()

        # The server logs the channel open failure - this is expected.
        errors = self.flushLoggedErrors(ConchError)
        self.assertIn('unknown channel',
                      (errors[0].value.data, errors[0].value.value))
        self.assertEqual(1, len(errors))

        # Now deal with the results on the endpoint side.
        f = self.failureResultOf(connected)
        f.trap(ConchError)
        self.assertEqual('unknown channel', f.value.value)

        # Nothing useful can be done with the connection at this point, so the
        # endpoint should close it.
        self.assertTrue(client.transport.disconnecting)
Beispiel #40
0
 def test_saveKeyBadFingerPrintformat(self):
     """
     L{_saveKey} raises C{keys.BadFingerprintFormat} when unsupported
     formats are requested.
     """
     base = FilePath(self.mktemp())
     base.makedirs()
     filename = base.child('id_rsa').path
     key = Key.fromString(privateRSA_openssh)
     with self.assertRaises(BadFingerPrintFormat) as em:
         _saveKey(key, {
             'filename': filename,
             'pass': '******',
             'format': 'sha-base64'
         })
     self.assertEqual('Unsupported fingerprint format: sha-base64',
                      em.exception.args[0])
Beispiel #41
0
    def getPublicKey(self):
        identities = self.options.get('identities')
        if not identities:
            return

        identity = os.path.expanduser(identities[0])
        if not os.path.exists(identity):
            return

        password = self.options.get('password', '')

        log.debug('Reading pubkey %s' % identity)
        try:
            data = ''.join(open(identity).readlines()).strip()
            self.key = Key.fromString(data, passphrase=password)
            return self.key
        except Exception:
            return
Beispiel #42
0
 def test_verifyKeyForHostAndIP(self):
     """
     Verifying a key where the hostname is present but the IP is not should
     result in the key being added for the IP and the user being warned
     about the change.
     """
     ui = FakeUI()
     hostsFile = self.loadSampleHostsFile()
     expectedKey = Key.fromString(sampleKey)
     hostsFile.verifyHostKey(
         ui, "www.twistedmatrix.com", "5.4.3.2", expectedKey)
     self.assertEqual(
         True, KnownHostsFile.fromPath(hostsFile.savePath).hasHostKey(
             "5.4.3.2", expectedKey))
     self.assertEqual(
         ["Warning: Permanently added the RSA host key for IP address "
          "'5.4.3.2' to the list of known hosts."],
         ui.userWarnings)
Beispiel #43
0
    def test_getPrivateKey(self):
        """
        L{SSHUserAuthClient.getPrivateKey} will load a private key from the
        last used file populated by L{SSHUserAuthClient.getPublicKey}, and
        return a L{Deferred} which fires with the corresponding private L{Key}.
        """
        rsaPrivate = Key.fromString(keydata.privateRSA_openssh)
        options = ConchOptions()
        options.identitys = [self.rsaFile.path]
        client = SSHUserAuthClient("user",  options, None)
        # Populate the list of used files
        client.getPublicKey()

        def _cbGetPrivateKey(key):
            self.assertEqual(key.isPublic(), False)
            self.assertEqual(key, rsaPrivate)

        return client.getPrivateKey().addCallback(_cbGetPrivateKey)
Beispiel #44
0
 def test_verifyHostButNotIP(self):
     """
     L{default.verifyHostKey} should return a L{Deferred} which fires with
     C{1} when passed a host which matches with an IP is not present in its
     known_hosts file, and should also warn the user that it has added the
     IP address.
     """
     l = []
     default.verifyHostKey(self.fakeTransport, "8.7.6.5", sampleKey,
                           "Fingerprint not required.").addCallback(l.append)
     self.assertEqual(
         ["Warning: Permanently added the RSA host key for IP address "
         "'8.7.6.5' to the list of known hosts."],
         self.fakeFile.outchunks)
     self.assertEqual([1], l)
     knownHostsFile = KnownHostsFile.fromPath(FilePath(self.hostsOption))
     self.assertEqual(True, knownHostsFile.hasHostKey("8.7.6.5",
                                          Key.fromString(sampleKey)))
Beispiel #45
0
 def test_savedEntryHasKeyMismatch(self):
     """
     L{KnownHostsFile.hasHostKey} raises L{HostKeyChanged} if the host key is
     present in the underlying file, but different from the expected one.
     The resulting exception should have an C{offendingEntry} indicating the
     given entry.
     """
     hostsFile = self.loadSampleHostsFile()
     entries = list(hostsFile.iterentries())
     exception = self.assertRaises(
         HostKeyChanged,
         hostsFile.hasHostKey,
         b"www.twistedmatrix.com",
         Key.fromString(otherSampleKey),
     )
     self.assertEqual(exception.offendingEntry, entries[0])
     self.assertEqual(exception.lineno, 1)
     self.assertEqual(exception.path, hostsFile.savePath)
 def setUp(self):
     """
     Patch 'open' in verifyHostKey.
     """
     self.fakeFile = FakeFile()
     self.patch(default, "_open", self.patchedOpen)
     self.hostsOption = self.mktemp()
     self.hashedEntries = {}
     knownHostsFile = KnownHostsFile(FilePath(self.hostsOption))
     for host in (b"exists.example.com", b"4.3.2.1"):
         entry = knownHostsFile.addHostKey(host, Key.fromString(sampleKey))
         self.hashedEntries[host] = entry
     knownHostsFile.save()
     self.fakeTransport = FakeObject()
     self.fakeTransport.factory = FakeObject()
     self.options = self.fakeTransport.factory.options = {
         'host': b"exists.example.com",
         'known-hosts': self.hostsOption
     }
Beispiel #47
0
 def test_saveKeyBadFingerPrintformat(self):
     """
     L{_saveKey} raises C{keys.BadFingerprintFormat} when unsupported
     formats are requested.
     """
     base = FilePath(self.mktemp())
     base.makedirs()
     filename = base.child("id_rsa").path
     key = Key.fromString(privateRSA_openssh)
     with self.assertRaises(BadFingerPrintFormat) as em:
         _saveKey(
             key,
             {
                 "filename": filename,
                 "pass": "******",
                 "format": "sha-base64"
             },
         )
     self.assertEqual("Unsupported fingerprint format: sha-base64",
                      em.exception.args[0])
    def test_addHostKey(self):
        """
        L{KnownHostsFile.addHostKey} adds a new L{HashedEntry} to the host
        file, and returns it.
        """
        hostsFile = self.loadSampleHostsFile()
        aKey = Key.fromString(thirdSampleKey)
        self.assertEqual(False,
                         hostsFile.hasHostKey("somewhere.example.com", aKey))
        newEntry = hostsFile.addHostKey("somewhere.example.com", aKey)

        # The code in OpenSSH requires host salts to be 20 characters long.
        # This is the required length of a SHA-1 HMAC hash, so it's just a
        # sanity check.
        self.assertEqual(20, len(newEntry._hostSalt))
        self.assertEqual(True, newEntry.matchesHost("somewhere.example.com"))
        self.assertEqual(newEntry.keyType, "ssh-rsa")
        self.assertEqual(aKey, newEntry.publicKey)
        self.assertEqual(True,
                         hostsFile.hasHostKey("somewhere.example.com", aKey))
Beispiel #49
0
    def _sanityCheckKey(self, credentials):
        """
        Check whether the provided credentials are a valid SSH key with a
        signature (does not actually verify the signature)

        @param credentials: The L{ISSHPrivateKey} provider credentials
            offered by the user.

        @raise ValidPublicKey: the credentials do not include a signature. See
            L{error.ValidPublicKey} for more information.

        @raise BadKeyError: the key included with the credentials is not
            recognized as a key

        @return: L{twisted.conch.ssh.keys.Key} of the key in the credentials
        """
        if not credentials.signature:
            raise ValidPublicKey()

        return Key.fromString(credentials.blob)
    def test_agentAuthentication(self):
        """
        If L{SSHCommandClientEndpoint} is initialized with an
        L{SSHAgentClient}, the agent is used to authenticate with the SSH
        server.
        """
        key = Key.fromString(privateRSA_openssh)
        agentServer = SSHAgentServer()
        agentServer.factory = Factory()
        agentServer.factory.keys = {key.blob(): (key, "")}

        self.setupKeyChecker(self.portal, {self.user: privateRSA_openssh})

        agentEndpoint = SingleUseMemoryEndpoint(agentServer)
        endpoint = SSHCommandClientEndpoint.newConnection(
            self.reactor,
            b"/bin/ls -l",
            self.user,
            self.hostname,
            self.port,
            knownHosts=self.knownHosts,
            ui=FixedResponseUI(False),
            agentEndpoint=agentEndpoint)

        self.realm.channelLookup[b'session'] = WorkingExecSession

        factory = Factory()
        factory.protocol = Protocol
        connected = endpoint.connect(factory)

        server, client, pump = self.connectedServerAndClient(
            self.factory, self.reactor.tcpClients[0][2])

        # Let the agent client talk with the agent server and the ssh client
        # talk with the ssh server.
        for i in range(14):
            agentEndpoint.pump.pump()
            pump.pump()

        protocol = self.successResultOf(connected)
        self.assertNotIdentical(None, protocol.transport)
Beispiel #51
0
    def checkKey(self, credentials):

        # dont bother checking until we've confirmed the key
        if not credentials.signature:
            return True

        cmp_key = Key.fromString(
            credentials.blob).fingerprint().replace(':', '')

        apiserver_base_url = '%s://%s:%d/' % (
            self.settings['apiserver_protocol'],
            self.settings['apiserver_hostname'],
            self.settings['apiserver_port']
        )

        lookup_url = '%sinternal/lookupUserByPublicKey?fingerprint=%s' % (
            apiserver_base_url ,cmp_key)

        log.msg("Checking fingerprint: " + lookup_url)

        d = defer.Deferred()

        def cbResponse(resp):
            if resp.code == 200:
                resp.deliverBody(UserExtractor(d, cmp_key, credentials))
            else:
                log.err('Key auth failed for ' + cmp_key)
                d.errback(False)

        def cbErrResponse(failure):
            log.err('Unable to contact api server')
            d.errback(False)

        auth_key = base64.b64encode(':%s' % self.settings['apiserver_key'])
        headers = Headers({'Authorization': [' Basic %s' % auth_key]})

        req = self.agent.request('GET', lookup_url, headers=headers)
        req.addCallback(cbResponse)
        req.addErrback(cbErrResponse)

        return d
def _extractCommon(string):
    """
    Extract common elements of base64 keys from an entry in a hosts file.

    @return: a 4-tuple of hostname data (L{str}), ssh key type (L{str}), key
    (L{Key}), and comment (L{str} or L{None}).  The hostname data is simply the
    beginning of the line up to the first occurrence of whitespace.
    """
    elements = string.split(None, 2)
    if len(elements) != 3:
        raise InvalidEntry()
    hostnames, keyType, keyAndComment = elements
    splitkey = keyAndComment.split(None, 1)
    if len(splitkey) == 2:
        keyString, comment = splitkey
        comment = comment.rstrip("\n")
    else:
        keyString = splitkey[0]
        comment = None
    key = Key.fromString(keyString.decode('base64'))
    return hostnames, keyType, key, comment
    def test_savingAddsEntry(self):
        """
        L{KnownHostsFile.save} will write out a new file with any entries
        that have been added.
        """
        path = self.pathWithContent(sampleHashedLine +
                                    otherSamplePlaintextLine)
        knownHostsFile = KnownHostsFile.fromPath(path)
        newEntry = knownHostsFile.addHostKey("some.example.com",
                                             Key.fromString(thirdSampleKey))
        expectedContent = (sampleHashedLine + otherSamplePlaintextLine +
                           HashedEntry.MAGIC +
                           b2a_base64(newEntry._hostSalt).strip() + "|" +
                           b2a_base64(newEntry._hostHash).strip() +
                           " ssh-rsa " + thirdSampleEncodedKey + "\n")

        # Sanity check, let's make sure the base64 API being used for the test
        # isn't inserting spurious newlines.
        self.assertEqual(3, expectedContent.count("\n"))
        knownHostsFile.save()
        self.assertEqual(expectedContent, path.getContent())
Beispiel #54
0
    def makeService(cls, config):
        """
		Create the txsftp service.
		"""
        if (conf.get('suppress-deprecation-warnings')):
            warnings.filterwarnings('ignore', r'.*', DeprecationWarning)

        get_key = lambda path: Key.fromString(data=open(path).read())
        ssh_public_key = get_key(conf.get('ssh-public-key'))
        ssh_private_key = get_key(conf.get('ssh-private-key'))

        factory = SSHFactory()
        factory.privateKeys = {'ssh-rsa': ssh_private_key}
        factory.publicKeys = {'ssh-rsa': ssh_public_key}

        db = dbapi.connect(conf.get('db-url'))
        factory.portal = Portal(auth.VirtualizedSSHRealm(db))
        factory.portal.registerChecker(auth.UsernamePasswordChecker(db))
        factory.portal.registerChecker(auth.SSHKeyChecker(db))

        return internet.TCPServer(conf.get('sftp-port'), factory)
    def setupKeyChecker(self, portal, users):
        """
        Create an L{ISSHPrivateKey} checker which recognizes C{users} and add it
        to C{portal}.

        @param portal: A L{Portal} to which to add the checker.
        @type portal: L{Portal}

        @param users: The users and their keys the checker will recognize.  Keys
            are byte strings giving user names.  Values are byte strings giving
            OpenSSH-formatted private keys.
        @type users: C{dict}
        """
        credentials = {}
        for username, keyString in users.iteritems():
            goodKey = Key.fromString(keyString)
            authorizedKeys = FilePath(self.mktemp())
            authorizedKeys.setContent(goodKey.public().toString("OPENSSH"))
            credentials[username] = [authorizedKeys]
        checker = MemorySSHPublicKeyDatabase(credentials)
        portal.registerChecker(checker)
Beispiel #56
0
 def _getKey(self):
     keyPath = os.path.expanduser(self.factory.keyPath)
     log.debug('Expanded SSH key path from zKeyPath %s to %s' %
               (self.factory.keyPath, keyPath))
     key = None
     if os.path.exists(keyPath):
         try:
             data = ''.join(open(keyPath).readlines()).strip()
             key = Key.fromString(data, passphrase=self.factory.password)
         except IOError, ex:
             message = "Unable to read the SSH key file because %s" % (
                 str(ex))
             log.warn(message)
             device = 'localhost'  # Fallback
             try:
                 device = socket.getfqdn()
             except:
                 pass
             sendEvent(self,
                       device=device,
                       message=message,
                       severity=Event.Warning)
Beispiel #57
0
    def get_ssh_key(self):
        """
        Return the public key associated with the provided keyname.

        :return Key: The ssh public key or ``None`` if it can't be determined.
        """
        try:
            key_pair = self._driver.get_key_pair(self._keyname)
        except Exception as e:
            if "RequestLimitExceeded" in e.message:
                # If we have run into API limits, we don't know if the key is
                # available. Re-raise the the exception, so that we can
                # accurately see the cause of the error.
                raise
            raise CloudKeyNotFound(self._keyname)
        if key_pair.public_key is not None:
            return Key.fromString(key_pair.public_key, type='public_openssh')
        else:
            # EC2 only provides the SSH2 fingerprint (for uploaded keys)
            # or the SHA-1 hash of the private key (for EC2 generated keys)
            # https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_KeyPairInfo.html
            return None
Beispiel #58
0
def gce_provisioner(
    zone, project, ssh_public_key, gce_credentials=None
):
    """
    Create an :class:`IProvisioner` for provisioning nodes on GCE.

    :param unicode zone: The name of the zone in which to provision instances.
    :param unicode project: The name of the project in which to provision
        instances.
    :param unicode ssh_public_key: The public key that will be put on the VM
        for ssh access.
    :param dict gce_credentials: A dict that has the same content as the json
        blob generated by the GCE console when you add a key to a service
        account. The service account must have permissions to spin up VMs in
        the specified project.

    :return: An class:`IProvisioner` provider for GCE instances.
    """
    key = Key.fromString(bytes(ssh_public_key))
    if gce_credentials is not None:
        credentials = SignedJwtAssertionCredentials(
            gce_credentials['client_email'],
            gce_credentials['private_key'],
            scope=[
                u"https://www.googleapis.com/auth/compute",
            ]
        )
    else:
        credentials = GoogleCredentials.get_application_default()
    compute = discovery.build('compute', 'v1', credentials=credentials)

    return GCEProvisioner(
        instance_builder=GCEInstanceBuilder(
            zone=unicode(zone),
            project=unicode(project),
            compute=compute,
        ),
        ssh_public_key=key,
    )
Beispiel #59
0
    def checkKey(self, credentials):
        # dont bother checking until we've confirmed the key
        if not credentials.signature:
            return True

        key = Key.fromString(credentials.blob)
        key_type, key_key = key_to_parts(key.toString('OPENSSH'))

        payload = {'key_key': key_key}
        params = {'api_key': self.settings['hadoukngit']['api_key']}
        url = '%s/users/key' % self.settings['hadoukngit']['api_url']

        r = requests.get(url, data=json.dumps(payload), params=params)

        if r.ok:
            user = r.json()
            credentials.username = '******' % (user['username'],
                                              user['api_key'])
            return True
        else:
            error = r.json()
            logger.info(error['msg'])
            return defer.fail()
Beispiel #60
0
    def test_saveKeyNoFilename(self):
        """
        When no path is specified, it will ask for the path used to store the
        key.
        """
        base = FilePath(self.mktemp())
        base.makedirs()
        keyPath = base.child("custom_key").path

        import twisted.conch.scripts.ckeygen

        self.patch(twisted.conch.scripts.ckeygen, "_inputSaveFile",
                   lambda _: keyPath)
        key = Key.fromString(privateRSA_openssh)
        _saveKey(key, {
            "filename": None,
            "no-passphrase": True,
            "format": "md5-hex"
        })

        persistedKeyContent = base.child("custom_key").getContent()
        persistedKey = key.fromString(persistedKeyContent, None, b"")
        self.assertEqual(key, persistedKey)