-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
config/server: add token_key
to avoid randomization of handshake token
#201
Conversation
I think this PR is good enough. This is more Actually, I am start thinking that we could just allow building a
Can you please provide more details about the worst case? I don't fully understand why we do have it in the first place (naively I would have said only "in-flight retry" could have been invalidated) |
Absolutely! I wrote code like this, reusing the same loop to avoid spawning an additional let config = new_config(port, &rustls_config);
let endpoint = Endpoint::server(config)?;
let mut reload_rate_limit = RateLimiter::new(Duration::from_secs(60));
loop {
if !reload_rate_limit.should_limit_rate() {
// may enter if branch every minute
// assumption: will enter at least once every 0.5 months, which is sufficient for Let's Encrypt
endpoint.reload_config(new_config(port, &rustls_config), false).unwrap();
}
let incoming_session = endpoint.accept().await;
if !incoming_session.remote_address_validated() {
incoming_session.retry();
continue;
}
tokio::spawn(async move {
let _ = incoming_session.await;
});
} The sequence of events is:
In other words, it's not that there is a reload and the next retry fails (as I originally thought and said). It's that the act of retrying causes the reload to happen at the same time, guaranteeing that the retry will be in-flight. I could have spawned an additional |
I see, so as I thought the problem is only for those in-flight "retries" after the config reload (which updates the token key). However, if so, the probability of this to happen is proportional to the frequency of reloading the configuration. Moreover, as you correctly mentioned. the main issue of your code is because:
essentially the problem is mixing "sync" and "async" code. More idiomatic code could be something like: loop {
// ...
// For example:
// https://docs.rs/tokio/latest/tokio/time/struct.Interval.html#
let interval_reload_config: tokio::time::Interval = /* ... */
tokio::select! {
() = interval_reload_config.tick() => {
// reload config
}
incoming = endpoint.accept() => {
// handle incoming
}
}
} More interesting instead is:
(Just want to be sure I am correctly understanding) Anyway that's probably the correct behavior as the standard says:
From: RFC9000$17.2.5.2 |
Yes, makes the failure rare instead of certain, which is an improvement 👍 But impossible is still better than rare. (I thought of a way to avoid failure without this PR: don't reload the config if sent a retry in last 10 seconds or whatever the retry token validity is set to, and hope that a 10s gap will exist within a 1 month period, which it certainly will for my app. If you want, I can change this PR to simply warn about this in the documentation of reload_config)
Yes, that's what I meant. This is based on instrumenting
Yeah, my guess is Chrome follows the spec and the 2nd, 3rd, 4th, etc. retries are ignored. Chrome is simply resending the first one, to account for the unreliable network. |
Actually I was more curious about the issue than relating this to the PR. In particular, I wanted to see if we had the fully comprehension of the root cause to properly prioritize this. This PR is fine, thank you for that. My only feeling is that this new API is quite "advanced-use", it also requires a little bit of understanding of the underlying protocol and crypto functions, in contrast with the philosophy of As mentioned, for this kind of "advanced-usage" probably the best option is just having a Thank you again for those contributions of yours; they are really appreciated! :) |
As followup of my comment, I've created #202 This remove exposing I'd glad if you want to take a look at the PR. Thank you |
Motivation
To refresh TLS certificates, the
Endpoint
config must be reloaded. If the new config has a different (random) handshake token, then best case in-flight retries will fail. Worst case (as in my application), the next retry will fail regardless of when it happens.Testing
rustls@0.23
andquinn@0.11
#200Changelog entry
Context
Followup to #200
Example code for generating a handshake token:
Unresolved questions
should the example code be included in the docs?should the example code be exposed from the API? (would requirering
andrand
deps, but they could be optional)or should I PRquinn-proto
to include it there?