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()
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()
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)
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''
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)
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()
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()
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)])
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()
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()
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()))
def simulate_rsa_done(self, sig): """Simulate receiving an RSA done packet""" self.process_packet(Byte(MSG_KEXRSA_DONE) + String(sig))
def simulate_rsa_secret(self, encrypted_k): """Simulate receiving an RSA secret packet""" self.process_packet(Byte(MSG_KEXRSA_SECRET) + String(encrypted_k))
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))
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))))
def simulate_ecdh_init(self, client_pub): """Simulate receiving an ECDH init packet""" self.process_packet(Byte(MSG_KEX_ECDH_INIT) + String(client_pub))
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))))
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))))
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)
def _encode_options(options): """Encode SSH certificate critical options and extensions""" return b''.join((String(k) + String(v) for k, v in options.items()))
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)))
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')
def __init__(self, response): self._response = b'' if response is None else String(response) self._path = None self._server = None
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)))
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)
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()
def test_unicode(self): """Unit test encoding of UTF-8 string""" self.assertEqual(String('\u2000'), b'\x00\x00\x00\x03\xe2\x80\x80')