Пример #1
0
    def test_add_remove_smartcard_keys(self):
        """Test adding and removing smart card keys"""

        mock_agent = _Agent(String(Byte(SSH_AGENT_SUCCESS)))
        yield from mock_agent.start('mock_agent')
        agent = yield from asyncssh.connect_agent('mock_agent')

        result = yield from agent.add_smartcard_keys('provider')
        self.assertIsNone(result)

        agent.close()
        yield from mock_agent.stop()

        mock_agent = _Agent(String(Byte(SSH_AGENT_SUCCESS)))
        yield from mock_agent.start('mock_agent')
        agent = yield from asyncssh.connect_agent('mock_agent')

        result = yield from agent.remove_smartcard_keys('provider')
        self.assertIsNone(result)

        agent.close()
        yield from mock_agent.stop()
Пример #2
0
    async def test_query_extensions(self):
        """Test query of supported extensions"""

        mock_agent = _Agent(Byte(SSH_AGENT_SUCCESS) + String('xxx'))
        await mock_agent.start('mock_agent')

        async with asyncssh.connect_agent('mock_agent') as agent:
            extensions = await agent.query_extensions()
            self.assertEqual(extensions, ['xxx'])

        await mock_agent.stop()

        mock_agent = _Agent(Byte(SSH_AGENT_SUCCESS) + String(b'\xff'))
        await mock_agent.start('mock_agent')

        async with asyncssh.connect_agent('mock_agent') as agent:
            with self.assertRaises(ValueError):
                await agent.query_extensions()

        await mock_agent.stop()

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

        async with asyncssh.connect_agent('mock_agent') as agent:
            extensions = await agent.query_extensions()
            self.assertEqual(extensions, [])

        await mock_agent.stop()

        mock_agent = _Agent(b'\xff')
        await mock_agent.start('mock_agent')

        async with asyncssh.connect_agent('mock_agent') as agent:
            with self.assertRaises(ValueError):
                await agent.query_extensions()

        await mock_agent.stop()
Пример #3
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(MSG_USERAUTH_GSSAPI_RESPONSE,
                                 String('mismatch'))
            elif self._override_pk_ok:
                self.send_packet(MSG_USERAUTH_PK_OK, String(''), String(''))
            else:
                self._auth = lookup_server_auth(self, 'user', method, packet)
        else:
            self._auth.process_packet(pkttype, None, packet)
Пример #4
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''
Пример #5
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)
Пример #6
0
    def test_forced_exec(self):
        """Test execution of a forced remote command"""

        ckey = asyncssh.read_private_key('ckey')
        cert = make_certificate('*****@*****.**',
                                CERT_TYPE_USER,
                                ckey,
                                ckey, ['ckey'],
                                options={'force-command': String('echo')})

        with (yield from self.connect(username='******',
                                      client_keys=[(ckey, cert)])) as conn:
            yield from self._check_session(conn)

        yield from conn.wait_closed()
Пример #7
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 (b'', String(b''), String(Byte(SSH_AGENT_FAILURE)),
                         String(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()
Пример #8
0
    def test_disallowed_address(self):
        """Test disallowed address in certificate"""

        ckey = asyncssh.read_private_key('ckey')
        skey = asyncssh.read_private_key('skey')

        cert = make_certificate('*****@*****.**',
                                CERT_TYPE_USER,
                                skey,
                                ckey, ['ckey'],
                                options={'source-address': String('0.0.0.0')})

        with self.assertRaises(asyncssh.DisconnectError):
            yield from self.connect(username='******',
                                    client_keys=[(skey, cert)])
Пример #9
0
    def test_allowed_address(self):
        """Test allowed address in certificate"""

        ckey = asyncssh.read_private_key('ckey')
        skey = asyncssh.read_private_key('skey')

        cert = make_certificate('*****@*****.**',
                                CERT_TYPE_USER, skey, ckey, ['ckey'],
                                options={'source-address':
                                         String('0.0.0.0/0,::/0')})

        with (yield from self.connect(username='******',
                                      client_keys=[(skey, cert)])) as conn:
            pass

        yield from conn.wait_closed()
Пример #10
0
    def test_query_extensions(self):
        """Test query of supported extensions"""

        mock_agent = _Agent(String(Byte(SSH_AGENT_SUCCESS) + String('xxx')))
        yield from mock_agent.start('mock_agent')
        agent = yield from asyncssh.connect_agent('mock_agent')

        extensions = yield from agent.query_extensions()
        self.assertEqual(extensions, ['xxx'])

        agent.close()
        yield from mock_agent.stop()

        mock_agent = _Agent(String(Byte(SSH_AGENT_SUCCESS) + String(b'\xff')))
        yield from mock_agent.start('mock_agent')
        agent = yield from asyncssh.connect_agent('mock_agent')

        with self.assertRaises(ValueError):
            yield from agent.query_extensions()

        agent.close()
        yield from mock_agent.stop()

        mock_agent = _Agent(String(Byte(SSH_AGENT_FAILURE)))
        yield from mock_agent.start('mock_agent')
        agent = yield from asyncssh.connect_agent('mock_agent')

        extensions = yield from agent.query_extensions()
        self.assertEqual(extensions, [])

        agent.close()
        yield from mock_agent.stop()

        mock_agent = _Agent(String(b'\xff'))
        yield from mock_agent.start('mock_agent')
        agent = yield from asyncssh.connect_agent('mock_agent')

        with self.assertRaises(ValueError):
            yield from agent.query_extensions()

        agent.close()
        yield from mock_agent.stop()
Пример #11
0
    def encode_options(self, options):
        """Encode SSH certificate critical options and extensions"""

        # pylint: disable=no-self-use

        return b''.join((String(k) + String(v) for k, v in options.items()))
Пример #12
0
    def simulate_rsa_done(self, sig):
        """Simulate receiving an RSA done packet"""

        self.process_packet(Byte(MSG_KEXRSA_DONE) + String(sig))
Пример #13
0
    def simulate_rsa_secret(self, encrypted_k):
        """Simulate receiving an RSA secret packet"""

        self.process_packet(Byte(MSG_KEXRSA_SECRET) + String(encrypted_k))
Пример #14
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))
Пример #15
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))))
Пример #16
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))
Пример #17
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))))
Пример #18
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))))
Пример #19
0
    def check_decode_errors(self):
        """Check error code paths in key decoding"""

        private_errors = [
            ('Non-ASCII', '\xff'), ('Incomplete ASN.1', b''),
            ('Invalid PKCS#1', der_encode(None)),
            ('Invalid PKCS#1 params',
             der_encode((1, b'', TaggedDERObject(0, b'')))),
            ('Invalid PKCS#1 EC named curve OID',
             der_encode((1, b'', TaggedDERObject(0,
                                                 ObjectIdentifier('1.1'))))),
            ('Invalid PKCS#8',
             der_encode((0, (self.privkey.pkcs8_oid, ()), der_encode(None)))),
            ('Invalid PKCS#8 ASN.1',
             der_encode((0, (self.privkey.pkcs8_oid, None), b''))),
            ('Invalid PKCS#8 params',
             der_encode(
                 (1, (self.privkey.pkcs8_oid, b''), der_encode((1, b''))))),
            ('Invalid PEM header', b'-----BEGIN XXX-----\n'),
            ('Missing PEM footer', b'-----BEGIN PRIVATE KEY-----\n'),
            ('Invalid PEM key type', b'-----BEGIN XXX PRIVATE KEY-----\n' +
             binascii.b2a_base64(der_encode(None)) +
             b'-----END XXX PRIVATE KEY-----'),
            ('Invalid PEM Base64', b'-----BEGIN PRIVATE KEY-----\n'
             b'X\n'
             b'-----END PRIVATE KEY-----'),
            ('Missing PKCS#1 passphrase', b'-----BEGIN DSA PRIVATE KEY-----\n'
             b'Proc-Type: 4,ENCRYPTED\n'
             b'-----END DSA PRIVATE KEY-----'),
            ('Incomplete PEM ASN.1', b'-----BEGIN PRIVATE KEY-----\n'
             b'-----END PRIVATE KEY-----'),
            ('Missing PEM PKCS#8 passphrase',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' +
             binascii.b2a_base64(der_encode(None)) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#1 key', b'-----BEGIN DSA PRIVATE KEY-----\n' +
             binascii.b2a_base64(der_encode(None)) +
             b'-----END DSA PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 key', b'-----BEGIN PRIVATE KEY-----\n' +
             binascii.b2a_base64(der_encode(None)) +
             b'-----END PRIVATE KEY-----'),
            ('Unknown format OpenSSH key',
             b'-----BEGIN OPENSSH PRIVATE KEY-----\n' +
             binascii.b2a_base64(b'XXX') +
             b'-----END OPENSSH PRIVATE KEY-----'),
            ('Incomplete OpenSSH key',
             b'-----BEGIN OPENSSH PRIVATE KEY-----\n' +
             binascii.b2a_base64(b'openssh-key-v1\0') +
             b'-----END OPENSSH PRIVATE KEY-----'),
            ('Invalid OpenSSH nkeys',
             b'-----BEGIN OPENSSH PRIVATE KEY-----\n' +
             binascii.b2a_base64(b''.join(
                 (b'openssh-key-v1\0', String(''), String(''), String(''),
                  UInt32(2), String(''), String('')))) +
             b'-----END OPENSSH PRIVATE KEY-----'),
            ('Missing OpenSSH passphrase',
             b'-----BEGIN OPENSSH PRIVATE KEY-----\n' +
             binascii.b2a_base64(b''.join(
                 (b'openssh-key-v1\0', String('xxx'), String(''), String(''),
                  UInt32(1), String(''), String('')))) +
             b'-----END OPENSSH PRIVATE KEY-----'),
            ('Mismatched OpenSSH check bytes',
             b'-----BEGIN OPENSSH PRIVATE KEY-----\n' +
             binascii.b2a_base64(b''.join(
                 (b'openssh-key-v1\0', String('none'), String(''), String(''),
                  UInt32(1), String(''),
                  String(b''.join((UInt32(1), UInt32(2))))))) +
             b'-----END OPENSSH PRIVATE KEY-----'),
            ('Invalid OpenSSH algorithm',
             b'-----BEGIN OPENSSH PRIVATE KEY-----\n' +
             binascii.b2a_base64(b''.join(
                 (b'openssh-key-v1\0', String('none'), String(''), String(''),
                  UInt32(1), String(''),
                  String(b''.join((UInt32(1), UInt32(1), String('xxx'))))))) +
             b'-----END OPENSSH PRIVATE KEY-----'),
            ('Invalid OpenSSH pad', b'-----BEGIN OPENSSH PRIVATE KEY-----\n' +
             binascii.b2a_base64(b''.join(
                 (b'openssh-key-v1\0', String('none'), String(''), String(''),
                  UInt32(1), String(''),
                  String(b''.join(
                      (UInt32(1), UInt32(1), String('ssh-dss'), 5 * MPInt(0),
                       String(''), b'\0')))))) +
             b'-----END OPENSSH PRIVATE KEY-----')
        ]

        decrypt_errors = [
            ('Invalid PKCS#1', der_encode(None)),
            ('Invalid PKCS#8',
             der_encode((0, (self.privkey.pkcs8_oid, ()), der_encode(None)))),
            ('Invalid PEM params', b'-----BEGIN DSA PRIVATE KEY-----\n'
             b'Proc-Type: 4,ENCRYPTED\n'
             b'DEK-Info: XXX\n'
             b'-----END DSA PRIVATE KEY-----'),
            ('Invalid PEM cipher', b'-----BEGIN DSA PRIVATE KEY-----\n'
             b'Proc-Type: 4,ENCRYPTED\n'
             b'DEK-Info: XXX,00\n'
             b'-----END DSA PRIVATE KEY-----'),
            ('Invalid PEM IV', b'-----BEGIN DSA PRIVATE KEY-----\n'
             b'Proc-Type: 4,ENCRYPTED\n'
             b'DEK-Info: AES-256-CBC,XXX\n'
             b'-----END DSA PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 encrypted data',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' +
             binascii.b2a_base64(der_encode(None)) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 encrypted header',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' +
             binascii.b2a_base64(der_encode(
                 (None, None))) + b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 encryption algorithm',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' +
             binascii.b2a_base64(der_encode(((None, None), b''))) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 PBES1 encryption parameters',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' +
             binascii.b2a_base64(der_encode(((_ES1_SHA1_DES, None), b''))) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 PBES1 PKCS#12 encryption parameters',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' +
             binascii.b2a_base64(der_encode(((_P12_RC4_40, None), b''))) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 PBES1 PKCS#12 salt',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' +
             binascii.b2a_base64(der_encode(
                 ((_P12_RC4_40,
                   (b'', 0)), b''))) + b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 PBES1 PKCS#12 iteration count',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' +
             binascii.b2a_base64(der_encode(((_P12_RC4_40, (b'x', 0)), b''))) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 PBES2 encryption parameters',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' +
             binascii.b2a_base64(der_encode(((_ES2, None), b''))) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 PBES2 KDF algorithm',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' + binascii.b2a_base64(
                 der_encode(((_ES2, ((None, None), (None, None))), b''))) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 PBES2 encryption algorithm',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' + binascii.b2a_base64(
                 der_encode(
                     ((_ES2, ((_ES2_PBKDF2, None), (None, None))), b''))) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 PBES2 PBKDF2 parameters',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' + binascii.b2a_base64(
                 der_encode(((_ES2, ((_ES2_PBKDF2, None),
                                     (_ES2_AES128, None))), b''))) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 PBES2 PBKDF2 salt',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' + binascii.b2a_base64(
                 der_encode(((_ES2, ((_ES2_PBKDF2, (None, None)),
                                     (_ES2_AES128, None))), b''))) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 PBES2 PBKDF2 iteration count',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' + binascii.b2a_base64(
                 der_encode(((_ES2, ((_ES2_PBKDF2, (b'', None)),
                                     (_ES2_AES128, None))), b''))) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 PBES2 PBKDF2 PRF',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' + binascii.b2a_base64(
                 der_encode(((_ES2, ((_ES2_PBKDF2, (b'', 0, None)),
                                     (_ES2_AES128, None))), b''))) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Unknown PEM PKCS#8 PBES2 PBKDF2 PRF',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' + binascii.b2a_base64(
                 der_encode(
                     ((_ES2, ((_ES2_PBKDF2, (b'', 0,
                                             (ObjectIdentifier('1.1'), None))),
                              (_ES2_AES128, None))), b''))) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid PEM PKCS#8 PBES2 encryption parameters',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' + binascii.b2a_base64(
                 der_encode(((_ES2, ((_ES2_PBKDF2, (b'', 0)),
                                     (_ES2_AES128, None))), b''))) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid length PEM PKCS#8 PBES2 IV',
             b'-----BEGIN ENCRYPTED PRIVATE KEY-----\n' + binascii.b2a_base64(
                 der_encode(((_ES2, ((_ES2_PBKDF2, (b'', 0)),
                                     (_ES2_AES128, b''))), b''))) +
             b'-----END ENCRYPTED PRIVATE KEY-----'),
            ('Invalid OpenSSH cipher',
             b'-----BEGIN OPENSSH PRIVATE KEY-----\n' +
             binascii.b2a_base64(b''.join(
                 (b'openssh-key-v1\0', String('xxx'), String(''), String(''),
                  UInt32(1), String(''), String('')))) +
             b'-----END OPENSSH PRIVATE KEY-----'),
            ('Invalid OpenSSH kdf', b'-----BEGIN OPENSSH PRIVATE KEY-----\n' +
             binascii.b2a_base64(b''.join(
                 (b'openssh-key-v1\0', String('aes256-cbc'), String('xxx'),
                  String(''), UInt32(1), String(''), String('')))) +
             b'-----END OPENSSH PRIVATE KEY-----'),
            ('Invalid OpenSSH kdf data',
             b'-----BEGIN OPENSSH PRIVATE KEY-----\n' +
             binascii.b2a_base64(b''.join(
                 (b'openssh-key-v1\0', String('aes256-cbc'), String('bcrypt'),
                  String(''), UInt32(1), String(''), String('')))) +
             b'-----END OPENSSH PRIVATE KEY-----'),
            ('Invalid OpenSSH salt', b'-----BEGIN OPENSSH PRIVATE KEY-----\n' +
             binascii.b2a_base64(b''.join(
                 (b'openssh-key-v1\0', String('aes256-cbc'), String('bcrypt'),
                  String(b''.join(
                      (String(b''), UInt32(1)))), UInt32(1), String(''),
                  String('')))) + b'-----END OPENSSH PRIVATE KEY-----'),
            ('Invalid OpenSSH encrypted data',
             b'-----BEGIN OPENSSH PRIVATE KEY-----\n' +
             binascii.b2a_base64(b''.join(
                 (b'openssh-key-v1\0', String('aes256-cbc'), String('bcrypt'),
                  String(b''.join(
                      (String(16 * b'\0'), UInt32(1)))), UInt32(1), String(''),
                  String('')))) + b'-----END OPENSSH PRIVATE KEY-----'),
            ('Unexpected OpenSSH trailing data',
             b'-----BEGIN OPENSSH PRIVATE KEY-----\n' +
             binascii.b2a_base64(b''.join(
                 (b'openssh-key-v1\0', String('aes256-cbc'), String('bcrypt'),
                  String(b''.join((String(16 * b'\0'), UInt32(1)))), UInt32(1),
                  String(''), String(''), String('xxx')))) +
             b'-----END OPENSSH PRIVATE KEY-----')
        ]

        public_errors = [
            ('Non-ASCII', '\xff'), ('Incomplete ASN.1', b''),
            ('Invalid ASN.1', b'\x30'), ('Invalid PKCS#1', der_encode(None)),
            ('Invalid PKCS#8',
             der_encode(
                 ((self.pubkey.pkcs8_oid, ()), BitString(der_encode(None))))),
            ('Invalid PKCS#8 ASN.1',
             der_encode(((self.pubkey.pkcs8_oid, None), BitString(b'')))),
            ('Invalid PEM header', b'-----BEGIN XXX-----\n'),
            ('Missing PEM footer', b'-----BEGIN PUBLIC KEY-----\n'),
            ('Invalid PEM key type', b'-----BEGIN XXX PUBLIC KEY-----\n' +
             binascii.b2a_base64(der_encode(None)) +
             b'-----END XXX PUBLIC KEY-----'),
            ('Invalid PEM Base64', b'-----BEGIN PUBLIC KEY-----\n'
             b'X\n'
             b'-----END PUBLIC KEY-----'),
            ('Incomplete PEM ASN.1', b'-----BEGIN PUBLIC KEY-----\n'
             b'-----END PUBLIC KEY-----'),
            ('Invalid PKCS#1 key data', b'-----BEGIN DSA PUBLIC KEY-----\n' +
             binascii.b2a_base64(der_encode(None)) +
             b'-----END DSA PUBLIC KEY-----'),
            ('Invalid PKCS#8 key data', b'-----BEGIN PUBLIC KEY-----\n' +
             binascii.b2a_base64(der_encode(None)) +
             b'-----END PUBLIC KEY-----'), ('Invalid OpenSSH', b'xxx'),
            ('Invalid OpenSSH Base64', b'ssh-dss X'),
            ('Unknown OpenSSH algorithm',
             b'ssh-dss ' + binascii.b2a_base64(String('xxx'))),
            ('Invalid OpenSSH body',
             b'ssh-dss ' + binascii.b2a_base64(String('ssh-dss'))),
            ('Invalid RFC4716 header', b'---- XXX ----\n'),
            ('Missing RFC4716 footer', b'---- BEGIN SSH2 PUBLIC KEY ----\n'),
            ('Invalid RFC4716 header', b'---- BEGIN SSH2 PUBLIC KEY ----\n'
             b'XXX:\\\n'
             b'---- END SSH2 PUBLIC KEY ----\n'),
            ('Invalid RFC4716 Base64', b'---- BEGIN SSH2 PUBLIC KEY ----\n'
             b'X\n'
             b'---- END SSH2 PUBLIC KEY ----\n')
        ]

        for fmt, data in private_errors:
            with self.subTest('Decode private (%s)' % fmt):
                with self.assertRaises(KeyImportError):
                    import_private_key(data)

        for fmt, data in decrypt_errors:
            with self.subTest('Decrypt private (%s)' % fmt):
                with self.assertRaises((KeyImportError, KeyEncryptionError)):
                    import_private_key(data, 'x')

        for fmt, data in public_errors:
            with self.subTest('Decode public (%s)' % fmt):
                with self.assertRaises(KeyImportError):
                    import_public_key(data)
Пример #20
0
def _encode_options(options):
    """Encode SSH certificate critical options and extensions"""

    return b''.join((String(k) + String(v) for k, v in options.items()))
Пример #21
0
    def make_x11_forwarding_request(self, proto, data, screen):
        """Make a request to enable X11 forwarding"""

        return (yield from self._make_request(b'x11-req', Boolean(False),
                                              String(proto), String(data),
                                              UInt32(screen)))
Пример #22
0
    def check_certificate_errors(self, cert_type):
        """Check SSH certificate error cases"""

        with self.subTest('Non-ASCII certificate'):
            with self.assertRaises(KeyImportError):
                import_certificate('\u0080\n')

        with self.subTest('Invalid SSH format'):
            with self.assertRaises(KeyImportError):
                import_certificate('xxx\n')

        with self.subTest('Invalid certificate packetization'):
            with self.assertRaises(KeyImportError):
                import_certificate(b'xxx ' + binascii.b2a_base64(b'\x00'))

        with self.subTest('Invalid certificate algorithm'):
            with self.assertRaises(KeyImportError):
                import_certificate(b'xxx ' +
                                   binascii.b2a_base64(String(b'xxx')))

        with self.subTest('Invalid certificate critical option'):
            with self.assertRaises(KeyImportError):
                cert = self.make_certificate(cert_type,
                                             self.pubkey,
                                             self.privca,
                                             'name',
                                             options={b'xxx': b''})
                import_certificate(cert)

        with self.subTest('Ignored certificate extension'):
            cert = self.make_certificate(cert_type,
                                         self.pubkey,
                                         self.privca,
                                         'name',
                                         extensions={b'xxx': b''})
            self.assertIsNotNone(import_certificate(cert))

        with self.subTest('Invalid certificate signature'):
            with self.assertRaises(KeyImportError):
                cert = self.make_certificate(cert_type,
                                             self.pubkey,
                                             self.privca,
                                             'name',
                                             bad_signature=True)
                import_certificate(cert)

        with self.subTest('Invalid characters in certificate principal'):
            with self.assertRaises(KeyImportError):
                cert = self.make_certificate(cert_type, self.pubkey,
                                             self.privca, (b'\xff', ))
                import_certificate(cert)

        if cert_type == CERT_TYPE_USER:
            with self.subTest('Invalid characters in force-command'):
                with self.assertRaises(KeyImportError):
                    cert = self.make_certificate(
                        cert_type,
                        self.pubkey,
                        self.privca, ('name', ),
                        options={'force-command': String(b'\xff')})
                    import_certificate(cert)

            with self.subTest('Invalid characters in source-address'):
                with self.assertRaises(KeyImportError):
                    cert = self.make_certificate(
                        cert_type,
                        self.pubkey,
                        self.privca, ('name', ),
                        options={'source-address': String(b'\xff')})
                    import_certificate(cert)

            with self.subTest('Invalid IP network in source-address'):
                with self.assertRaises(KeyImportError):
                    cert = self.make_certificate(
                        cert_type,
                        self.pubkey,
                        self.privca, ('name', ),
                        options={'source-address': String('1.1.1.256')})
                    import_certificate(cert)

        with self.subTest('Invalid certificate type'):
            with self.assertRaises(KeyImportError):
                cert = self.make_certificate(0, self.pubkey, self.privca,
                                             ('name', ))
                import_certificate(cert)

        with self.subTest('Mismatched certificate type'):
            with self.assertRaises(ValueError):
                cert = self.make_certificate(cert_type, self.pubkey,
                                             self.privca, ('name', ))
                cert = import_certificate(cert)
                cert.validate(cert_type ^ 3, 'name')

        with self.subTest('Certificate not yet valid'):
            with self.assertRaises(ValueError):
                cert = self.make_certificate(cert_type,
                                             self.pubkey,
                                             self.privca, ('name', ),
                                             valid_after=0xffffffffffffffff)
                cert = import_certificate(cert)
                cert.validate(cert_type, 'name')

        with self.subTest('Certificate expired'):
            with self.assertRaises(ValueError):
                cert = self.make_certificate(cert_type,
                                             self.pubkey,
                                             self.privca, ('name', ),
                                             valid_before=0)
                cert = import_certificate(cert)
                cert.validate(cert_type, 'name')

        with self.subTest('Certificate principal mismatch'):
            with self.assertRaises(ValueError):
                cert = self.make_certificate(cert_type, self.pubkey,
                                             self.privca, ('name', ))
                cert = import_certificate(cert)
                cert.validate(cert_type, 'name2')
Пример #23
0
 def __init__(self, response):
     self._response = b'' if response is None else String(response)
     self._path = None
     self._server = None
Пример #24
0
def make_certificate(cert_version,
                     cert_type,
                     key,
                     signing_key,
                     principals,
                     key_id='name',
                     valid_after=0,
                     valid_before=0xffffffffffffffff,
                     options=None,
                     extensions=None,
                     bad_signature=False):
    """Construct an SSH certificate"""

    keydata = key.encode_ssh_public()
    principals = b''.join((String(p) for p in principals))
    options = _encode_options(options) if options else b''
    extensions = _encode_options(extensions) if extensions else b''
    signing_keydata = b''.join(
        (String(signing_key.algorithm), signing_key.encode_ssh_public()))

    data = b''.join(
        (String(cert_version), String(os.urandom(32)), keydata, UInt64(0),
         UInt32(cert_type), String(key_id), String(principals),
         UInt64(valid_after), UInt64(valid_before), String(options),
         String(extensions), String(''), String(signing_keydata)))

    if bad_signature:
        data += String('')
    else:
        data += String(signing_key.sign(data, signing_key.algorithm))

    return b''.join(
        (cert_version.encode('ascii'), b' ', binascii.b2a_base64(data)))
Пример #25
0
    def get_userauth_request_data(self, method, *args):
        """Get signature data for a user authentication request"""

        return String('') + self._get_userauth_request_packet(method, args)
Пример #26
0
    async 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':
            await echo(stdin, stdout, stderr)
        elif action == 'conn_close':
            await stdin.read(1)
            stdout.write('\n')
            self._conn.close()
        elif action == 'close':
            await stdin.read(1)
            stdout.write('\n')
        elif action == 'agent':
            try:
                async with asyncssh.connect_agent(self._conn) as agent:
                    stdout.write(str(len((await agent.get_keys()))) + '\n')
            except (OSError, asyncssh.ChannelOpenError):
                stdout.channel.exit(1)
        elif action == 'agent_sock':
            agent_path = stdin.channel.get_agent_path()

            if agent_path:
                async with asyncssh.connect_agent(agent_path) as agent:
                    stdout.write(str(len((await agent.get_keys()))) + '\n')
            else:
                stdout.channel.exit(1)
        elif action == 'rejected_agent':
            agent_path = stdin.channel.get_agent_path()
            stdout.write(str(bool(agent_path)) + '\n')

            chan = self._conn.create_agent_channel()

            try:
                await chan.open(SSHUNIXStreamSession)
            except asyncssh.ChannelOpenError:
                stdout.channel.exit(1)
        elif action == 'rejected_session':
            chan = _ServerChannel(self._conn, asyncio.get_event_loop(), False,
                                  False, 0, None, 'strict', 1, 32768)

            try:
                await chan.open_session()
            except asyncssh.ChannelOpenError:
                stdout.channel.exit(1)
        elif action == 'rejected_tcpip_direct':
            chan = self._conn.create_tcp_channel()

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

            try:
                await 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:
                await 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:
                await chan.connect(SSHUNIXStreamSession, '')
            except asyncssh.ChannelOpenError:
                stdout.channel.exit(1)
        elif action == 'unknown_unix_listener':
            chan = self._conn.create_unix_channel()

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

            try:
                await 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:
                await 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('INT', False, 'exit_signal')
        elif action == 'unknown_signal':
            stdin.channel.exit_with_signal('unknown', False, 'unknown_signal')
        elif action == 'closed_signal':
            stdin.channel.close()
            stdin.channel.exit_with_signal('INT', False, 'closed_signal')
        elif action == 'invalid_exit_signal':
            stdin.channel.exit_with_signal('invalid')
        elif action == 'invalid_exit_lang':
            stdin.channel.exit_with_signal('INT', 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':
            await 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':
            await 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(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()
        await stdin.channel.wait_closed()
Пример #27
0
    def test_unicode(self):
        """Unit test encoding of UTF-8 string"""

        self.assertEqual(String('\u2000'), b'\x00\x00\x00\x03\xe2\x80\x80')