async def test_tls_reject_certificate(): cli_ctx = get_client_ssl_context() serv_ctx = get_server_ssl_context() # These certs are not signed by our test CA bad_cert_key = ("tls-self-signed-cert.pem", "tls-self-signed-key.pem") bad_cli_ctx = get_client_ssl_context(*bad_cert_key) bad_serv_ctx = get_server_ssl_context(*bad_cert_key) async def handle_comm(comm): scheme, loc = parse_address(comm.peer_address) assert scheme == "tls" await comm.close() # Listener refuses a connector not signed by the CA listener = await listen( "tls://", handle_comm, connection_args={"ssl_context": serv_ctx} ) with pytest.raises(EnvironmentError) as excinfo: comm = await connect( listener.contact_address, timeout=0.5, connection_args={"ssl_context": bad_cli_ctx}, ) await comm.write({"x": "foo"}) # TODO: why is this necessary in Tornado 6 ? # The wrong error is reported on Python 2, see https://github.com/tornadoweb/tornado/pull/2028 if sys.version_info >= (3,) and os.name != "nt": try: # See https://serverfault.com/questions/793260/what-does-tlsv1-alert-unknown-ca-mean assert "unknown ca" in str(excinfo.value) except AssertionError: if os.name == "nt": assert "An existing connection was forcibly closed" in str( excinfo.value ) else: raise # Sanity check comm = await connect( listener.contact_address, timeout=2, connection_args={"ssl_context": cli_ctx} ) await comm.close() # Connector refuses a listener not signed by the CA listener = await listen( "tls://", handle_comm, connection_args={"ssl_context": bad_serv_ctx} ) with pytest.raises(EnvironmentError) as excinfo: await connect( listener.contact_address, timeout=2, connection_args={"ssl_context": cli_ctx}, ) # The wrong error is reported on Python 2, see https://github.com/tornadoweb/tornado/pull/2028 if sys.version_info >= (3,): assert "certificate verify failed" in str(excinfo.value)
def test_tls_reject_certificate(): cli_ctx = get_client_ssl_context() serv_ctx = get_server_ssl_context() # These certs are not signed by our test CA bad_cert_key = ('tls-self-signed-cert.pem', 'tls-self-signed-key.pem') bad_cli_ctx = get_client_ssl_context(*bad_cert_key) bad_serv_ctx = get_server_ssl_context(*bad_cert_key) @gen.coroutine def handle_comm(comm): scheme, loc = parse_address(comm.peer_address) assert scheme == 'tls' yield comm.close() # Listener refuses a connector not signed by the CA listener = listen('tls://', handle_comm, connection_args={'ssl_context': serv_ctx}) listener.start() with pytest.raises(EnvironmentError) as excinfo: yield connect(listener.contact_address, timeout=0.5, connection_args={'ssl_context': bad_cli_ctx}) # The wrong error is reported on Python 2, see https://github.com/tornadoweb/tornado/pull/2028 if sys.version_info >= (3, ) and os.name != 'nt': try: # See https://serverfault.com/questions/793260/what-does-tlsv1-alert-unknown-ca-mean assert "unknown ca" in str(excinfo.value) except AssertionError: if os.name == 'nt': assert "An existing connection was forcibly closed" in str( excinfo.value) else: raise # Sanity check comm = yield connect(listener.contact_address, timeout=0.5, connection_args={'ssl_context': cli_ctx}) yield comm.close() # Connector refuses a listener not signed by the CA listener = listen('tls://', handle_comm, connection_args={'ssl_context': bad_serv_ctx}) listener.start() with pytest.raises(EnvironmentError) as excinfo: yield connect(listener.contact_address, timeout=0.5, connection_args={'ssl_context': cli_ctx}) # The wrong error is reported on Python 2, see https://github.com/tornadoweb/tornado/pull/2028 if sys.version_info >= (3, ): assert "certificate verify failed" in str(excinfo.value)
def test_tls_reject_certificate(): cli_ctx = get_client_ssl_context() serv_ctx = get_server_ssl_context() # These certs are not signed by our test CA bad_cert_key = ('tls-self-signed-cert.pem', 'tls-self-signed-key.pem') bad_cli_ctx = get_client_ssl_context(*bad_cert_key) bad_serv_ctx = get_server_ssl_context(*bad_cert_key) @gen.coroutine def handle_comm(comm): scheme, loc = parse_address(comm.peer_address) assert scheme == 'tls' yield comm.close() # Listener refuses a connector not signed by the CA listener = listen('tls://', handle_comm, connection_args={'ssl_context': serv_ctx}) listener.start() with pytest.raises(EnvironmentError) as excinfo: yield connect(listener.contact_address, timeout=0.5, connection_args={'ssl_context': bad_cli_ctx}) # The wrong error is reported on Python 2, see https://github.com/tornadoweb/tornado/pull/2028 if sys.version_info >= (3,) and os.name != 'nt': try: # See https://serverfault.com/questions/793260/what-does-tlsv1-alert-unknown-ca-mean assert "unknown ca" in str(excinfo.value) except AssertionError: if os.name == 'nt': assert "An existing connection was forcibly closed" in str(excinfo.value) else: raise # Sanity check comm = yield connect(listener.contact_address, timeout=0.5, connection_args={'ssl_context': cli_ctx}) yield comm.close() # Connector refuses a listener not signed by the CA listener = listen('tls://', handle_comm, connection_args={'ssl_context': bad_serv_ctx}) listener.start() with pytest.raises(EnvironmentError) as excinfo: yield connect(listener.contact_address, timeout=0.5, connection_args={'ssl_context': cli_ctx}) # The wrong error is reported on Python 2, see https://github.com/tornadoweb/tornado/pull/2028 if sys.version_info >= (3,): assert "certificate verify failed" in str(excinfo.value)
async def test_comm_failure_threading(): """ When we fail to connect, make sure we don't make a lot of threads. We only assert for PY3, because the thread limit only is set for python 3. See github PR #2403 discussion for info. """ async def sleep_for_60ms(): max_thread_count = 0 for x in range(60): await asyncio.sleep(0.001) thread_count = threading.active_count() if thread_count > max_thread_count: max_thread_count = thread_count return max_thread_count original_thread_count = threading.active_count() # tcp.TCPConnector() sleep_future = sleep_for_60ms() with pytest.raises(IOError): await connect("tcp://localhost:28400", 0.052) max_thread_count = await sleep_future # 2 is the number set by BaseTCPConnector.executor (ThreadPoolExecutor) assert max_thread_count <= 2 + original_thread_count # tcp.TLSConnector() sleep_future = sleep_for_60ms() with pytest.raises(IOError): await connect("tls://localhost:28400", 0.052, ssl_context=get_client_ssl_context()) max_thread_count = await sleep_future assert max_thread_count <= 2 + original_thread_count
async def test_tls_reject_certificate(tcp): cli_ctx = get_client_ssl_context() serv_ctx = get_server_ssl_context() # These certs are not signed by our test CA bad_cert_key = ("tls-self-signed-cert.pem", "tls-self-signed-key.pem") bad_cli_ctx = get_client_ssl_context(*bad_cert_key) bad_serv_ctx = get_server_ssl_context(*bad_cert_key) async def handle_comm(comm): scheme, loc = parse_address(comm.peer_address) assert scheme == "tls" await comm.close() # Listener refuses a connector not signed by the CA listener = await listen("tls://", handle_comm, ssl_context=serv_ctx) with pytest.raises(EnvironmentError) as excinfo: comm = await connect(listener.contact_address, timeout=0.5, ssl_context=bad_cli_ctx) await comm.write({"x": "foo"}) # TODO: why is this necessary in Tornado 6 ? if os.name != "nt": try: # See https://serverfault.com/questions/793260/what-does-tlsv1-alert-unknown-ca-mean # assert "unknown ca" in str(excinfo.value) pass except AssertionError: if os.name == "nt": assert "An existing connection was forcibly closed" in str( excinfo.value) else: raise # Sanity check comm = await connect(listener.contact_address, timeout=2, ssl_context=cli_ctx) await comm.close() # Connector refuses a listener not signed by the CA listener = await listen("tls://", handle_comm, ssl_context=bad_serv_ctx) with pytest.raises(EnvironmentError) as excinfo: await connect(listener.contact_address, timeout=2, ssl_context=cli_ctx)
def test_tls_specific(): """ Test concrete TLS API. """ @gen.coroutine def handle_comm(comm): assert comm.peer_address.startswith("tls://" + host) check_tls_extra(comm.extra_info) msg = yield comm.read() msg["op"] = "pong" yield comm.write(msg) yield comm.close() server_ctx = get_server_ssl_context() client_ctx = get_client_ssl_context() listener = tcp.TLSListener("localhost", handle_comm, ssl_context=server_ctx) listener.start() host, port = listener.get_host_port() assert host in ("localhost", "127.0.0.1", "::1") assert port > 0 connector = tcp.TLSConnector() l = [] @gen.coroutine def client_communicate(key, delay=0): addr = "%s:%d" % (host, port) comm = yield connector.connect(addr, ssl_context=client_ctx) assert comm.peer_address == "tls://" + addr check_tls_extra(comm.extra_info) yield comm.write({"op": "ping", "data": key}) if delay: yield gen.sleep(delay) msg = yield comm.read() assert msg == {"op": "pong", "data": key} l.append(key) yield comm.close() yield client_communicate(key=1234) # Many clients at once N = 100 futures = [client_communicate(key=i, delay=0.05) for i in range(N)] yield futures assert set(l) == {1234} | set(range(N))
def test_tls_specific(): """ Test concrete TLS API. """ @gen.coroutine def handle_comm(comm): assert comm.peer_address.startswith('tls://' + host) check_tls_extra(comm.extra_info) msg = yield comm.read() msg['op'] = 'pong' yield comm.write(msg) yield comm.close() server_ctx = get_server_ssl_context() client_ctx = get_client_ssl_context() listener = tcp.TLSListener('localhost', handle_comm, ssl_context=server_ctx) listener.start() host, port = listener.get_host_port() assert host in ('localhost', '127.0.0.1', '::1') assert port > 0 connector = tcp.TLSConnector() l = [] @gen.coroutine def client_communicate(key, delay=0): addr = '%s:%d' % (host, port) comm = yield connector.connect(addr, ssl_context=client_ctx) assert comm.peer_address == 'tls://' + addr check_tls_extra(comm.extra_info) yield comm.write({'op': 'ping', 'data': key}) if delay: yield gen.sleep(delay) msg = yield comm.read() assert msg == {'op': 'pong', 'data': key} l.append(key) yield comm.close() yield client_communicate(key=1234) # Many clients at once N = 100 futures = [client_communicate(key=i, delay=0.05) for i in range(N)] yield futures assert set(l) == {1234} | set(range(N))
async def test_listen_connect_wss(): async def handle_comm(comm): while True: msg = await comm.read() await comm.write(msg) server_ctx = get_server_ssl_context() client_ctx = get_client_ssl_context() async with listen("wss://", handle_comm, ssl_context=server_ctx) as listener: comm = await connect(listener.contact_address, ssl_context=client_ctx) assert comm.peer_address.startswith("wss://") check_tls_extra(comm.extra_info) await comm.write(b"Hello!") result = await comm.read() assert result == b"Hello!" await comm.close()
async def test_tls_specific(tcp): """ Test concrete TLS API. """ async def handle_comm(comm): assert comm.peer_address.startswith("tls://" + host) check_tls_extra(comm.extra_info) msg = await comm.read() msg["op"] = "pong" await comm.write(msg) await comm.close() server_ctx = get_server_ssl_context() client_ctx = get_client_ssl_context() listener = await tcp.TLSListener("127.0.0.1", handle_comm, ssl_context=server_ctx) host, port = listener.get_host_port() assert host in ("localhost", "127.0.0.1", "::1") assert port > 0 l = [] async def client_communicate(key, delay=0): addr = "%s:%d" % (host, port) comm = await connect(listener.contact_address, ssl_context=client_ctx) assert comm.peer_address == "tls://" + addr check_tls_extra(comm.extra_info) await comm.write({"op": "ping", "data": key}) if delay: await asyncio.sleep(delay) msg = await comm.read() assert msg == {"op": "pong", "data": key} l.append(key) await comm.close() await client_communicate(key=1234) # Many clients at once N = 100 futures = [client_communicate(key=i, delay=0.05) for i in range(N)] await asyncio.gather(*futures) assert set(l) == {1234} | set(range(N))
def test_comm_failure_threading(): """ When we fail to connect, make sure we don't make a lot of threads. We only assert for PY3, because the thread limit only is set for python 3. See github PR #2403 discussion for info. """ @gen.coroutine def sleep_for_60ms(): max_thread_count = 0 for x in range(60): yield gen.sleep(0.001) thread_count = threading.active_count() if thread_count > max_thread_count: max_thread_count = thread_count raise gen.Return(max_thread_count) original_thread_count = threading.active_count() # tcp.TCPConnector() sleep_future = sleep_for_60ms() with pytest.raises(IOError): yield connect("tcp://localhost:28400", 0.052) max_thread_count = yield sleep_future # 2 is the number set by BaseTCPConnector.executor (ThreadPoolExecutor) if PY3: assert max_thread_count <= 2 + original_thread_count # tcp.TLSConnector() sleep_future = sleep_for_60ms() with pytest.raises(IOError): yield connect( "tls://localhost:28400", 0.052, connection_args={"ssl_context": get_client_ssl_context()}, ) max_thread_count = yield sleep_future if PY3: assert max_thread_count <= 2 + original_thread_count
) def check_tls_extra(info): assert isinstance(info, dict) assert info['peercert']['subject'] == cert_subject assert 'cipher' in info cipher_name, proto_name, secret_bits = info['cipher'] # Most likely assert 'AES' in cipher_name assert 'TLS' in proto_name assert secret_bits >= 128 tls_kwargs = dict(listen_args={'ssl_context': get_server_ssl_context()}, connect_args={'ssl_context': get_client_ssl_context()}) @gen.coroutine def get_comm_pair(listen_addr, listen_args=None, connect_args=None, **kwargs): q = queues.Queue() def handle_comm(comm): q.put(comm) listener = listen(listen_addr, handle_comm, connection_args=listen_args, **kwargs) listener.start() comm = yield connect(listener.contact_address,
def check_tls_extra(info): assert isinstance(info, dict) assert info["peercert"]["subject"] == cert_subject assert "cipher" in info cipher_name, proto_name, secret_bits = info["cipher"] # Most likely assert "AES" in cipher_name assert "TLS" in proto_name assert secret_bits >= 128 tls_kwargs = dict( listen_args={"ssl_context": get_server_ssl_context()}, connect_args={"ssl_context": get_client_ssl_context()}, ) @gen.coroutine def get_comm_pair(listen_addr, listen_args=None, connect_args=None, **kwargs): q = queues.Queue() def handle_comm(comm): q.put(comm) listener = listen(listen_addr, handle_comm, connection_args=listen_args, **kwargs) listener.start()
'localhost'), )) def check_tls_extra(info): assert isinstance(info, dict) assert info['peercert']['subject'] == cert_subject assert 'cipher' in info cipher_name, proto_name, secret_bits = info['cipher'] # Most likely assert 'AES' in cipher_name assert 'TLS' in proto_name assert secret_bits >= 128 tls_kwargs = dict(listen_args={'ssl_context': get_server_ssl_context()}, connect_args={'ssl_context': get_client_ssl_context()}) @gen.coroutine def get_comm_pair(listen_addr, listen_args=None, connect_args=None, **kwargs): q = queues.Queue() def handle_comm(comm): q.put(comm) listener = listen(listen_addr, handle_comm, connection_args=listen_args, **kwargs) listener.start()