question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

TLS server only performs handshake after 'accept' is called

See original GitHub issue

Hi,

I would expect the following code to work:

import anyio
import ssl

async def main():
	server_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
	server_context.load_cert_chain(certfile="cert.pem", keyfile="key.pem")
	
	client_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
	client_context.load_verify_locations(cafile="cert.pem")
	
	async with await anyio.create_tcp_server(1234, ssl_context=server_context) as server:
		async with await anyio.connect_tcp("localhost", 1234, ssl_context=client_context, autostart_tls=True) as client:
			print("connected") # This line is never reached
			conn = await server.accept()

anyio.run(main)

However, it gets stuck in anyio.connect_tcp. If I disable autostart_tls it connects fine but gets stuck when I call start_tls on the client. It seems like the server is only able to perform the TLS handshake if I call accept on the server object, as the following code works fine:

import anyio
import ssl

async def task(server):
	conn = await server.accept()
	await conn.close()

async def main():
	server_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
	server_context.load_cert_chain(certfile="cert.pem", keyfile="key.pem")
	
	client_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
	client_context.load_verify_locations(cafile="cert.pem")
	
	async with await anyio.create_tcp_server(1234, ssl_context=server_context) as server:
		async with anyio.create_task_group() as tg:
			await tg.spawn(task, server)
			async with await anyio.connect_tcp("localhost", 1234, ssl_context=client_context, autostart_tls=True) as client:
				print("connected") # This works fine

anyio.run(main)

I don’t think this is the intended behavior?

The behavior seems to be the same across all backends.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:16 (9 by maintainers)

github_iconTop GitHub Comments

2reactions
agronholmcommented, Jul 22, 2020

Yes the code looks complex, but it’s also correct and, what’s more, it is a prime example of how to run SSL over any stream whatsoever. I’m somewhat less interested in a TLS implementation that’s integrated into the “standard” kernel-based networking framework in such a way that if you ever need to run TLS over something else you need another implementation.

I have a huge number of changes sitting in my local repository which, among many other things, decouple the TLS implementation from any socket functionality whatsoever and let you negotiate TLS over any arbitrary receive/send stream pair, just like trio does. These changes are very hard to separate from each other which is why I have elected not to push to master until I have much broader test coverage – something I’m actively working on.

1reaction
agronholmcommented, Jul 14, 2020

I also wonder if this can lead to other issues at the server side. accept only returns after the handshake has succeeded. But that means that nothing is calling accept while the server is accepting a TLS connection. Imagine that a client is trying to connect that is really slow (perhaps even on purpose). Is the server still able to perform handshakes with other clients while it is waiting for the slow client to send its client certificate? Or does this effectively cause a denial of service?

You raise a good point here. I was about to refactor the serving/listening system to work more like trio anyway, so I’ll make sure that accept() is only called in a dedicated task.

Read more comments on GitHub >

github_iconTop Results From Across the Web

What happens in a TLS handshake? | SSL ... - Cloudflare
A TLS handshake takes place whenever a user navigates to a website over HTTPS and the browser first begins to query the website's...
Read more >
Taking a Closer Look at the SSL/TLS Handshake
The 'SSL/TLS handshake' is the technical name for the process that establishes an HTTPS connection. Most of the hard work involved in the...
Read more >
An overview of the SSL or TLS handshake - IBM
The SSL or TLS handshake enables the SSL or TLS client and server to establish the secret keys with which they communicate.
Read more >
TLS Handshake : Under The Hood - Medium
The handshake protocol involves four sets of messages that are exchanged between the client and server before establishing the encrypted ...
Read more >
Networking 101: Transport Layer Security (TLS)
The TLS protocol specifies a well-defined handshake sequence to perform this ... The server may respond with only a single protocol name, and...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found