Пример #1
0
    def authenticate(self, message_hash, app_hash, key_handle):
        """Sign a message with a security key using CTAP version 1"""

        self._poll()

        if self.dev.error == 'nocred':
            raise ApduError(APDU.WRONG_DATA, b'')
        elif self.dev.error == 'err':
            raise ApduError(0, b'')

        flags, counter, sig = self._sign(message_hash, app_hash, key_handle,
                                         SSH_SK_USER_PRESENCE_REQD)

        return Byte(flags) + UInt32(counter) + sig
Пример #2
0
    def process_packet(self, data):
        """Process an incoming packet"""

        packet = SSHPacket(data)
        pkttype = packet.get_byte()

        if pkttype == MSG_USERAUTH_REQUEST:
            _ = packet.get_string()         # username
            _ = packet.get_string()         # service
            method = packet.get_string()

            if self._auth:
                self._auth.cancel()

            if self._override_gss_mech:
                self.send_packet(Byte(MSG_USERAUTH_GSSAPI_RESPONSE),
                                 String('mismatch'))
            elif self._override_pk_ok:
                self.send_packet(Byte(MSG_USERAUTH_PK_OK),
                                 String(''), String(''))
            else:
                self._auth = lookup_server_auth(self, 'user', method, packet)
        else:
            self._auth.process_packet(pkttype, packet)
Пример #3
0
    async def test_get_sk_keys(self):
        """Test getting U2F security keys"""

        key = asyncssh.generate_private_key(
            '*****@*****.**')
        cert = key.generate_user_certificate(key, 'test')

        mock_agent = _Agent(Byte(SSH_AGENT_IDENTITIES_ANSWER) + UInt32(2) +
                            String(key.public_data) + String('') +
                            String(cert.public_data) + String(''))

        await mock_agent.start('mock_agent')

        async with asyncssh.connect_agent('mock_agent') as agent:
            await agent.get_keys()

        await mock_agent.stop()
Пример #4
0
    def _sign(message_hash, app_hash, key_handle, flags):
        """Sign a message with a security key"""

        alg, public_value, private_value = der_decode(key_handle)

        if alg == SSH_SK_ECDSA:
            key = ECDSAPrivateKey.construct(
                b'nistp256', public_value,
                int.from_bytes(private_value, 'big'))
        else:
            key = EdDSAPrivateKey.construct(b'ed25519', private_value)

        counter = 0x12345678

        sig = key.sign(app_hash + Byte(flags) + UInt32(counter) + message_hash)

        return flags, counter, sig
Пример #5
0
    async def test_add_sk_keys(self):
        """Test adding U2F security keys"""

        key = asyncssh.generate_private_key(
            '*****@*****.**')
        cert = key.generate_user_certificate(key, 'test')

        mock_agent = _Agent(Byte(SSH_AGENT_SUCCESS))
        await mock_agent.start('mock_agent')

        async with asyncssh.connect_agent('mock_agent') as agent:
            for keypair in asyncssh.load_keypairs([key, (key, cert)]):
                async with agent:
                    self.assertIsNone(await agent.add_keys([keypair]))

            async with agent:
                with self.assertRaises(asyncssh.KeyExportError):
                    await agent.add_keys([key.convert_to_public()])

        await mock_agent.stop()
Пример #6
0
    async def test_add_keys_failure(self, agent):
        """Test getting keys from the agent"""

        os.mkdir('.ssh', 0o700)
        key = asyncssh.generate_private_key('ssh-rsa')
        key.write_private_key(Path('.ssh', 'id_rsa'))

        try:
            mock_agent = _Agent(Byte(SSH_AGENT_FAILURE))
            await mock_agent.start('mock_agent')

            async with asyncssh.connect_agent('mock_agent') as agent:
                async with agent:
                    await agent.add_keys()

                async with agent:
                    with self.assertRaises(ValueError):
                        await agent.add_keys([key])
        finally:
            os.remove(os.path.join('.ssh', 'id_rsa'))
            os.rmdir('.ssh')
Пример #7
0
    def communicate(self, request):
        """Process SSH key signing request"""

        # pylint: disable=no-self-use

        packet = SSHPacket(request)
        request = packet.get_string()
        packet.check_end()

        packet = SSHPacket(request)
        version = packet.get_byte()
        _ = packet.get_uint32()  # sock_fd
        data = packet.get_string()
        packet.check_end()

        if version == 0:
            return b'', b''
        elif version == 1:
            return b'', b'invalid request'
        else:
            skey = asyncssh.load_keypairs('skey')[0]
            sig = skey.sign(data)
            return String(Byte(KEYSIGN_VERSION) + String(sig)), b''
Пример #8
0
    async def test_errors(self):
        """Test getting error responses from SSH agent"""

        key = asyncssh.generate_private_key('ssh-rsa')
        keypair = asyncssh.load_keypairs(key)[0]

        for response in (None, b'', Byte(SSH_AGENT_FAILURE), b'\xff'):
            mock_agent = _Agent(response)
            await mock_agent.start('mock_agent')

            async with asyncssh.connect_agent('mock_agent') as agent:
                for request in (agent.get_keys(), agent.sign(b'xxx', b'test'),
                                agent.add_keys([key]),
                                agent.add_smartcard_keys('xxx'),
                                agent.remove_keys([keypair]),
                                agent.remove_smartcard_keys('xxx'),
                                agent.remove_all(), agent.lock('passphrase'),
                                agent.unlock('passphrase')):
                    async with agent:
                        with self.assertRaises(ValueError):
                            await request

            await mock_agent.stop()
Пример #9
0
    def process_packet(self, data):
        """Process an incoming packet"""

        packet = SSHPacket(data)
        pkttype = packet.get_byte()

        if pkttype == MSG_USERAUTH_REQUEST:
            _ = packet.get_string()  # username
            _ = packet.get_string()  # service
            method = packet.get_string()

            if self._auth:
                self._auth.cancel()

            if self._override_pk_ok:
                self.send_packet(Byte(MSG_USERAUTH_PK_OK), String(''),
                                 String(''))
            else:
                self._auth = lookup_server_auth(self, 'user', method, packet)
        else:
            try:
                self._auth.process_packet(pkttype, packet)
            except DisconnectError as exc:
                self.connection_lost(exc)
Пример #10
0
    def simulate_ecdh_reply(self, host_key_data, server_pub, sig):
        """Simulate receiving ab ECDH reply packet"""

        self.process_packet(b''.join(
            (Byte(MSG_KEX_ECDH_REPLY), String(host_key_data),
             String(server_pub), String(sig))))
Пример #11
0
    def simulate_ecdh_init(self, client_pub):
        """Simulate receiving an ECDH init packet"""

        self.process_packet(Byte(MSG_KEX_ECDH_INIT) + String(client_pub))
Пример #12
0
    def simulate_gss_complete(self, f, sig):
        """Simulate receiving a GSS complete packet"""

        self.process_packet(b''.join((Byte(MSG_KEXGSS_COMPLETE), MPInt(f),
                                      String(sig), Boolean(False))))
Пример #13
0
    def simulate_dh_gex_reply(self, host_key_data, f, sig):
        """Simulate receiving a DH GEX reply packet"""

        self.process_packet(b''.join(
            (Byte(MSG_KEX_DH_GEX_REPLY), String(host_key_data), MPInt(f),
             String(sig))))
Пример #14
0
    def simulate_dh_gex_init(self, e):
        """Simulate receiving a DH GEX init packet"""

        self.process_packet(Byte(MSG_KEX_DH_GEX_INIT) + MPInt(e))
Пример #15
0
    def simulate_dh_gex_group(self, p, g):
        """Simulate receiving a DH GEX group packet"""

        self.process_packet(Byte(MSG_KEX_DH_GEX_GROUP) + MPInt(p) + MPInt(g))
Пример #16
0
    def simulate_rsa_done(self, sig):
        """Simulate receiving an RSA done packet"""

        self.process_packet(Byte(MSG_KEXRSA_DONE) + String(sig))
Пример #17
0
    def simulate_rsa_pubkey(self, host_key_data, trans_key_data):
        """Simulate receiving an RSA pubkey packet"""

        self.process_packet(
            Byte(MSG_KEXRSA_PUBKEY) + String(host_key_data) +
            String(trans_key_data))
Пример #18
0
    def _begin_session(self, stdin, stdout, stderr):
        """Begin processing a new session"""

        # pylint: disable=too-many-statements

        action = stdin.channel.get_command() or stdin.channel.get_subsystem()
        if not action:
            action = 'echo'

        if action == 'echo':
            yield from echo(stdin, stdout, stderr)
        elif action == 'conn_close':
            yield from stdin.read(1)
            stdout.write('\n')
            self._conn.close()
        elif action == 'close':
            yield from stdin.read(1)
            stdout.write('\n')
        elif action == 'agent':
            agent = yield from asyncssh.connect_agent(self._conn)
            if agent:
                stdout.write(str(len((yield from agent.get_keys()))) + '\n')
                agent.close()
            else:
                stdout.channel.exit(1)
        elif action == 'rejected_agent':
            chan = SSHAgentChannel(self._conn, asyncio.get_event_loop(), None,
                                   1, 32768)

            try:
                yield from chan.open(SSHUNIXStreamSession)
            except asyncssh.ChannelOpenError:
                stdout.channel.exit(1)
        elif action == 'rejected_session':
            chan = SSHClientChannel(self._conn, asyncio.get_event_loop(), None,
                                    1, 32768)

            try:
                yield from chan.create(SSHClientStreamSession, None, None, {},
                                       None, None, None, False)
            except asyncssh.ChannelOpenError:
                stdout.channel.exit(1)
        elif action == 'rejected_tcpip_direct':
            chan = self._conn.create_tcp_channel()

            try:
                yield from chan.connect(SSHTCPStreamSession, '', 0, '', 0)
            except asyncssh.ChannelOpenError:
                stdout.channel.exit(1)
        elif action == 'unknown_tcpip_listener':
            chan = self._conn.create_tcp_channel()

            try:
                yield from chan.accept(SSHTCPStreamSession, 'xxx', 0, '', 0)
            except asyncssh.ChannelOpenError:
                stdout.channel.exit(1)
        elif action == 'invalid_tcpip_listener':
            chan = self._conn.create_tcp_channel()

            try:
                yield from chan.accept(SSHTCPStreamSession, b'\xff', 0, '', 0)
            except asyncssh.ChannelOpenError:
                stdout.channel.exit(1)
        elif action == 'rejected_unix_direct':
            chan = self._conn.create_unix_channel()

            try:
                yield from chan.connect(SSHUNIXStreamSession, '')
            except asyncssh.ChannelOpenError:
                stdout.channel.exit(1)
        elif action == 'unknown_unix_listener':
            chan = self._conn.create_unix_channel()

            try:
                yield from chan.accept(SSHUNIXStreamSession, 'xxx')
            except asyncssh.ChannelOpenError:
                stdout.channel.exit(1)
        elif action == 'invalid_unix_listener':
            chan = self._conn.create_unix_channel()

            try:
                yield from chan.accept(SSHUNIXStreamSession, b'\xff')
            except asyncssh.ChannelOpenError:
                stdout.channel.exit(1)
        elif action == 'late_auth_banner':
            try:
                self._conn.send_auth_banner('auth banner')
            except OSError:
                stdin.channel.exit(1)
        elif action == 'invalid_open_confirm':
            stdin.channel.send_packet(MSG_CHANNEL_OPEN_CONFIRMATION, UInt32(0),
                                      UInt32(0), UInt32(0))
        elif action == 'invalid_open_failure':
            stdin.channel.send_packet(MSG_CHANNEL_OPEN_FAILURE, UInt32(0),
                                      String(''), String(''))
        elif action == 'env':
            value = stdin.channel.get_environment().get('TEST', '')
            stdout.write(value + '\n')
        elif action == 'term':
            chan = stdin.channel
            info = str((chan.get_terminal_type(), chan.get_terminal_size(),
                        chan.get_terminal_mode(asyncssh.PTY_OP_OSPEED)))
            stdout.write(info + '\n')
        elif action == 'xon_xoff':
            stdin.channel.set_xon_xoff(True)
        elif action == 'no_xon_xoff':
            stdin.channel.set_xon_xoff(False)
        elif action == 'signals':
            try:
                yield from stdin.readline()
            except asyncssh.BreakReceived as exc:
                stdin.channel.exit_with_signal('ABRT', False, str(exc.msec))
            except asyncssh.SignalReceived as exc:
                stdin.channel.exit_with_signal('ABRT', False, exc.signal)
            except asyncssh.TerminalSizeChanged as exc:
                size = (exc.width, exc.height, exc.pixwidth, exc.pixheight)
                stdin.channel.exit_with_signal('ABRT', False, str(size))
        elif action == 'exit_status':
            stdin.channel.exit(1)
        elif action == 'closed_status':
            stdin.channel.close()
            stdin.channel.exit(1)
        elif action == 'exit_signal':
            stdin.channel.exit_with_signal('ABRT', False, 'exit_signal')
        elif action == 'closed_signal':
            stdin.channel.close()
            stdin.channel.exit_with_signal('ABRT', False, 'closed_signal')
        elif action == 'invalid_exit_signal':
            stdin.channel.exit_with_signal('invalid')
        elif action == 'invalid_exit_lang':
            stdin.channel.exit_with_signal('ABRT', False, '', 'invalid')
        elif action == 'window_after_close':
            stdin.channel.send_packet(MSG_CHANNEL_CLOSE)
            stdin.channel.send_packet(MSG_CHANNEL_WINDOW_ADJUST, UInt32(0))
        elif action == 'empty_data':
            stdin.channel.send_packet(MSG_CHANNEL_DATA, String(''))
        elif action == 'partial_unicode':
            data = '\xff\xff'.encode('utf-8')
            stdin.channel.send_packet(MSG_CHANNEL_DATA, String(data[:3]))
            stdin.channel.send_packet(MSG_CHANNEL_DATA, String(data[3:]))
        elif action == 'partial_unicode_at_eof':
            data = '\xff\xff'.encode('utf-8')
            stdin.channel.send_packet(MSG_CHANNEL_DATA, String(data[:3]))
        elif action == 'unicode_error':
            stdin.channel.send_packet(MSG_CHANNEL_DATA, String(b'\xff'))
        elif action == 'data_past_window':
            stdin.channel.send_packet(MSG_CHANNEL_DATA,
                                      String(2 * 1025 * 1024 * '\0'))
        elif action == 'data_after_eof':
            stdin.channel.send_packet(MSG_CHANNEL_EOF)
            stdout.write('xxx')
        elif action == 'data_after_close':
            yield from asyncio.sleep(0.1)
            stdout.write('xxx')
        elif action == 'ext_data_after_eof':
            stdin.channel.send_packet(MSG_CHANNEL_EOF)
            stdin.channel.write_stderr('xxx')
        elif action == 'invalid_datatype':
            stdin.channel.send_packet(MSG_CHANNEL_EXTENDED_DATA, UInt32(255),
                                      String(''))
        elif action == 'double_eof':
            stdin.channel.send_packet(MSG_CHANNEL_EOF)
            stdin.channel.write_eof()
        elif action == 'double_close':
            yield from asyncio.sleep(0.1)
            stdout.write('xxx')
            stdin.channel.send_packet(MSG_CHANNEL_CLOSE)
        elif action == 'request_after_close':
            stdin.channel.send_packet(MSG_CHANNEL_CLOSE)
            stdin.channel.exit(1)
        elif action == 'unexpected_auth':
            self._conn.send_packet(Byte(MSG_USERAUTH_REQUEST), String('guest'),
                                   String('ssh-connection'), String('none'))
        elif action == 'invalid_response':
            stdin.channel.send_packet(MSG_CHANNEL_SUCCESS)
        else:
            stdin.channel.exit(255)

        stdin.channel.close()
        yield from stdin.channel.wait_closed()
Пример #19
0
    def simulate_rsa_secret(self, encrypted_k):
        """Simulate receiving an RSA secret packet"""

        self.process_packet(Byte(MSG_KEXRSA_SECRET) + String(encrypted_k))
Пример #20
0
    def send_userauth_failure(self, partial_success):
        """Send a user authentication failure response"""

        self._auth = None
        self.send_packet(Byte(MSG_USERAUTH_FAILURE), NameList([]),
                         Boolean(partial_success))
Пример #21
0
    def test_gss_errors(self):
        """Unit test error conditions in GSS key exchange"""

        client_conn, server_conn = \
            _KexClientStub.make_pair(b'gss-group1-sha1-mech', '3')

        with self.subTest('Init sent to client'):
            with self.assertRaises(asyncssh.ProtocolError):
                client_conn.process_packet(Byte(MSG_KEXGSS_INIT))

        with self.subTest('Complete sent to server'):
            with self.assertRaises(asyncssh.ProtocolError):
                server_conn.process_packet(Byte(MSG_KEXGSS_COMPLETE))

        with self.subTest('Exchange failed to complete'):
            with self.assertRaises(asyncssh.ProtocolError):
                client_conn.simulate_gss_complete(1, b'succeed')

        with self.subTest('Error sent to server'):
            with self.assertRaises(asyncssh.ProtocolError):
                server_conn.process_packet(Byte(MSG_KEXGSS_ERROR))

        client_conn.close()
        server_conn.close()

        with self.subTest('Signature verification failure'):
            with self.assertRaises(asyncssh.KeyExchangeFailed):
                yield from self._check_kex(b'gss-group1-sha1-mech', '0,fail')

        with self.subTest('Empty token in init'):
            with self.assertRaises(asyncssh.ProtocolError):
                yield from self._check_kex(b'gss-group1-sha1-mech',
                                           '0,empty_init')

        with self.subTest('Empty token in continue'):
            with self.assertRaises(asyncssh.ProtocolError):
                yield from self._check_kex(b'gss-group1-sha1-mech',
                                           '1,empty_continue')

        with self.subTest('Token after complete'):
            with self.assertRaises(asyncssh.ProtocolError):
                yield from self._check_kex(b'gss-group1-sha1-mech',
                                           '0,continue_token')

        for steps in range(2):
            with self.subTest('Token after complete', steps=steps):
                with self.assertRaises(asyncssh.ProtocolError):
                    yield from self._check_kex(b'gss-group1-sha1-mech',
                                               str(steps) + ',extra_token')

        with self.subTest('Context not secure'):
            with self.assertRaises(asyncssh.ProtocolError):
                yield from self._check_kex(b'gss-group1-sha1-mech',
                                           '1,no_server_integrity')

        with self.subTest('GSS error'):
            with self.assertRaises(asyncssh.KeyExchangeFailed):
                yield from self._check_kex(b'gss-group1-sha1-mech',
                                           '1,step_error')

        with self.subTest('GSS error with error token'):
            with self.assertRaises(asyncssh.KeyExchangeFailed):
                yield from self._check_kex(b'gss-group1-sha1-mech',
                                           '1,step_error,errtok')
Пример #22
0
    def send_userauth_success(self):
        """Send a user authentication success response"""

        self._auth = None
        self.send_packet(Byte(MSG_USERAUTH_SUCCESS))