Skip to content

Commit af882a6

Browse files
fix(iroh)!: Update dependencies & fix 0-RTT with newer rustls by pulling the expected NodeId out of the ServerName in verifiers (#3290)
## Description This is code that will both update deps like #3288 but also makes 0-RTT tests pass again. They were failing due to a [change in `rustls`](https://github.com/rustls/rustls/releases/tag/v%2F0.23.24): > Behavior change: Clients no longer offer resumption between different `ClientConfig`s that share a resumption store but do not share server certificate verification and client authentication credentials. If you share a resumption store between multiple `ClientConfig`s, please ensure their server certificate verification and client authentication credentials are also shared. Please read the new documentation on the `ClientConfig::resumption` item for details. > > Additionally, if you share a resumption store or ticketer between multiple `ServerConfig`s, please see the new documentation on `ServerConfig` about this. Essentially what they're doing is [checking that the certificate verifiers are `Arc::prt_eq` and depending on that allow or disallow 0-RTT](https://github.com/rustls/rustls/pull/2361/files#diff-9d58cb90e1df25604b88544aca7ea999ccd23bc5657384e196e77f407c0f4acfR256). When running the tests with rustls logging enabled, I confirmed that this is indeed what's happening: > [TRACE rustls::msgs::persist] resumption not allowed between different ServerCertVerifiers --- The fix isn't straight-forward. The reason we're creating new `ServerVerifier`s every time is that we're passing in the expected remote node ID every time. There used to be no other way of grabbing the other node's ID in the verifier, until, coincidentally #3146 landed, which changed the server name that's set when connecting from always being `localhost` to `<base32 NodeId>.iroh.invalid`. I'm now pulling in that value from the `ServerName` that's passed to the `ServerCertificateVerifier` in `verify_server_cert`. As far as I understand that value *should* be a client-set value not a value we get over the network. The downside of doing this is that we'll not be compatible with iroh versions that don't use the `<base32 NodeId>.iroh.invalid` server names. --- There's an unrelated change in here that's changing `make_client_config` and `make_server_config` infallible, as was done in #3161, which will definitely also have merge conflicts with this PR. ## Breaking Changes - `Router::spawn` is now a plain function instead of an `async fn` - `Router::spawn` is now infallible, instead of returning `anyhow::Result<()>` ## Change checklist <!-- Remove any that are not relevant. --> - [x] Self-review. - [x] Documentation updates following the [style guide](https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html#appendix-a-full-conventions-text), if relevant. - [x] All breaking changes documented. - [x] List all breaking changes in the above "Breaking Changes" section. --------- Co-authored-by: dignifiedquire <me@dignifiedquire.com>
1 parent a62a2bd commit af882a6

File tree

11 files changed

+663
-620
lines changed

11 files changed

+663
-620
lines changed

Cargo.lock

Lines changed: 464 additions & 475 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deny.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ allow = [
99
"BSD-2-Clause",
1010
"BSD-3-Clause",
1111
"BSL-1.0", # BOSL license
12+
"CDLA-Permissive-2.0", # Community Data License Agreement Permissive 2.0 due to webpki-root-certs
1213
"ISC",
1314
"MIT",
1415
"Zlib",

iroh/examples/echo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ async fn start_accept_side() -> Result<Router> {
7070
let endpoint = Endpoint::builder().discovery_n0().bind().await?;
7171

7272
// Build our protocol handler and add our protocol, identified by its ALPN, and spawn the node.
73-
let router = Router::builder(endpoint).accept(ALPN, Echo).spawn().await?;
73+
let router = Router::builder(endpoint).accept(ALPN, Echo).spawn();
7474

7575
Ok(router)
7676
}

iroh/examples/search.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ async fn main() -> Result<()> {
8585
let builder = Router::builder(endpoint);
8686

8787
// Add our protocol, identified by our ALPN, to the node, and spawn the node.
88-
let router = builder.accept(ALPN, proto.clone()).spawn().await?;
88+
let router = builder.accept(ALPN, proto.clone()).spawn();
8989

9090
match args.command {
9191
Command::Listen { text } => {

iroh/src/endpoint.rs

Lines changed: 21 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use std::{
2222
};
2323

2424
use anyhow::{bail, Context, Result};
25-
use data_encoding::BASE32_DNSSEC;
2625
use ed25519_dalek::{pkcs8::DecodePublicKey, VerifyingKey};
2726
use iroh_base::{NodeAddr, NodeId, RelayUrl, SecretKey};
2827
use iroh_relay::RelayMap;
@@ -78,16 +77,6 @@ pub use super::magicsock::{
7877
/// is still no connection the configured [`Discovery`] will be used however.
7978
const DISCOVERY_WAIT_PERIOD: Duration = Duration::from_millis(500);
8079

81-
/// Maximum amount of TLS tickets we will cache (by default) for 0-RTT connection
82-
/// establishment.
83-
///
84-
/// 8 tickets per remote endpoint, 32 different endpoints would max out the required storage:
85-
/// ~200 bytes per session + certificates (which are ~387 bytes)
86-
/// So 8 * 32 * (200 + 387) = 150.272 bytes, assuming pointers to certificates
87-
/// are never aliased pointers (they're Arc'ed).
88-
/// I think 150KB is an acceptable default upper limit for such a cache.
89-
const MAX_TLS_TICKETS: usize = 8 * 32;
90-
9180
type DiscoveryBuilder = Box<dyn FnOnce(&SecretKey) -> Option<Box<dyn Discovery>> + Send + Sync>;
9281

9382
/// Defines the mode of path selection for all traffic flowing through
@@ -175,9 +164,8 @@ impl Builder {
175164
.unwrap_or_else(|| SecretKey::generate(rand::rngs::OsRng));
176165
let static_config = StaticConfig {
177166
transport_config: Arc::new(self.transport_config),
178-
tls_auth: self.tls_auth,
167+
tls_config: tls::TlsConfig::new(self.tls_auth, secret_key.clone()),
179168
keylog: self.keylog,
180-
secret_key: secret_key.clone(),
181169
};
182170
#[cfg(not(wasm_browser))]
183171
let dns_resolver = self.dns_resolver.unwrap_or_default();
@@ -191,7 +179,7 @@ impl Builder {
191179
1 => Some(discovery.into_iter().next().expect("checked length")),
192180
_ => Some(Box::new(ConcurrentDiscovery::from_services(discovery))),
193181
};
194-
let server_config = static_config.create_server_config(self.alpn_protocols)?;
182+
let server_config = static_config.create_server_config(self.alpn_protocols);
195183

196184
let metrics = EndpointMetrics::default();
197185

@@ -544,22 +532,21 @@ impl Builder {
544532
/// Configuration for a [`quinn::Endpoint`] that cannot be changed at runtime.
545533
#[derive(Debug)]
546534
struct StaticConfig {
547-
tls_auth: tls::Authentication,
548-
secret_key: SecretKey,
535+
tls_config: tls::TlsConfig,
549536
transport_config: Arc<quinn::TransportConfig>,
550537
keylog: bool,
551538
}
552539

553540
impl StaticConfig {
554541
/// Create a [`quinn::ServerConfig`] with the specified ALPN protocols.
555-
fn create_server_config(&self, alpn_protocols: Vec<Vec<u8>>) -> Result<ServerConfig> {
556-
let quic_server_config =
557-
self.tls_auth
558-
.make_server_config(&self.secret_key, alpn_protocols, self.keylog)?;
542+
fn create_server_config(&self, alpn_protocols: Vec<Vec<u8>>) -> ServerConfig {
543+
let quic_server_config = self
544+
.tls_config
545+
.make_server_config(alpn_protocols, self.keylog);
559546
let mut server_config = ServerConfig::with_crypto(Arc::new(quic_server_config));
560547
server_config.transport_config(self.transport_config.clone());
561548

562-
Ok(server_config)
549+
server_config
563550
}
564551
}
565552

@@ -596,8 +583,6 @@ pub struct Endpoint {
596583
rtt_actor: Arc<rtt_actor::RttHandle>,
597584
/// Configuration structs for quinn, holds the transport config, certificate setup, secret key etc.
598585
static_config: Arc<StaticConfig>,
599-
/// Cache for TLS session keys we receive.
600-
session_store: Arc<dyn rustls::client::ClientSessionStore>,
601586
}
602587

603588
impl Endpoint {
@@ -616,7 +601,7 @@ impl Endpoint {
616601
///
617602
/// This is for internal use, the public interface is the [`Builder`] obtained from
618603
/// [Self::builder]. See the methods on the builder for documentation of the parameters.
619-
#[instrument("ep", skip_all, fields(me = %static_config.secret_key.public().fmt_short()))]
604+
#[instrument("ep", skip_all, fields(me = %static_config.tls_config.secret_key.public().fmt_short()))]
620605
async fn bind(static_config: StaticConfig, msock_opts: magicsock::Options) -> Result<Self> {
621606
let msock = magicsock::MagicSock::spawn(msock_opts).await?;
622607
trace!("created magicsock");
@@ -626,9 +611,6 @@ impl Endpoint {
626611
msock: msock.clone(),
627612
rtt_actor: Arc::new(rtt_actor::RttHandle::new(msock.metrics.magicsock.clone())),
628613
static_config: Arc::new(static_config),
629-
session_store: Arc::new(rustls::client::ClientSessionMemoryCache::new(
630-
MAX_TLS_TICKETS,
631-
)),
632614
};
633615
Ok(ep)
634616
}
@@ -637,10 +619,9 @@ impl Endpoint {
637619
///
638620
/// This will only affect new incoming connections.
639621
/// Note that this *overrides* the current list of ALPNs.
640-
pub fn set_alpns(&self, alpns: Vec<Vec<u8>>) -> Result<()> {
641-
let server_config = self.static_config.create_server_config(alpns)?;
622+
pub fn set_alpns(&self, alpns: Vec<Vec<u8>>) {
623+
let server_config = self.static_config.create_server_config(alpns);
642624
self.msock.endpoint().set_server_config(Some(server_config));
643-
Ok(())
644625
}
645626

646627
// # Methods for establishing connectivity.
@@ -758,28 +739,16 @@ impl Endpoint {
758739
let client_config = {
759740
let mut alpn_protocols = vec![alpn.to_vec()];
760741
alpn_protocols.extend(options.additional_alpns);
761-
let quic_client_config = self.static_config.tls_auth.make_client_config(
762-
&self.static_config.secret_key,
763-
node_id,
764-
alpn_protocols,
765-
Some(self.session_store.clone()),
766-
self.static_config.keylog,
767-
)?;
742+
let quic_client_config = self
743+
.static_config
744+
.tls_config
745+
.make_client_config(alpn_protocols, self.static_config.keylog);
768746
let mut client_config = quinn::ClientConfig::new(Arc::new(quic_client_config));
769747
client_config.transport_config(transport_config);
770748
client_config
771749
};
772750

773-
// We used to use a constant "localhost" for this - however, that would put all of
774-
// the TLS session tickets we receive into the same bucket in the TLS session ticket cache.
775-
// So we choose something that'd dependent on the NodeId.
776-
// We cannot use hex to encode the NodeId, as that'd encode to 64 characters, but we only
777-
// have 63 maximum per DNS subdomain. Base32 is the next best alternative.
778-
// We use the `.invalid` TLD, as that's specified (in RFC 2606) to never actually resolve
779-
// "for real", unlike `.localhost` which is allowed to resolve to `127.0.0.1`.
780-
// We also add "iroh" as a subdomain, although those 5 bytes might not be necessary.
781-
// We *could* decide to remove that indicator in the future likely without breakage.
782-
let server_name = &format!("{}.iroh.invalid", BASE32_DNSSEC.encode(node_id.as_bytes()));
751+
let server_name = &tls::name::encode(node_id);
783752
let connect = self.msock.endpoint().connect_with(
784753
client_config,
785754
mapped_addr.private_socket_addr(),
@@ -883,15 +852,15 @@ impl Endpoint {
883852

884853
/// Returns the secret_key of this endpoint.
885854
pub fn secret_key(&self) -> &SecretKey {
886-
&self.static_config.secret_key
855+
&self.static_config.tls_config.secret_key
887856
}
888857

889858
/// Returns the node id of this endpoint.
890859
///
891860
/// This ID is the unique addressing information of this node and other peers must know
892861
/// it to be able to connect to this node.
893862
pub fn node_id(&self) -> NodeId {
894-
self.static_config.secret_key.public()
863+
self.static_config.tls_config.secret_key.public()
895864
}
896865

897866
/// Returns the current [`NodeAddr`] for this endpoint.
@@ -1571,7 +1540,7 @@ impl Future for IncomingFuture {
15711540
Poll::Ready(Ok(inner)) => {
15721541
let conn = Connection {
15731542
inner,
1574-
tls_auth: this.ep.static_config.tls_auth,
1543+
tls_auth: this.ep.static_config.tls_config.auth,
15751544
};
15761545
try_send_rtt_msg(&conn, this.ep, None);
15771546
Poll::Ready(Ok(conn))
@@ -1644,7 +1613,7 @@ impl Connecting {
16441613
Ok((inner, zrtt_accepted)) => {
16451614
let conn = Connection {
16461615
inner,
1647-
tls_auth: self.ep.static_config.tls_auth,
1616+
tls_auth: self.ep.static_config.tls_config.auth,
16481617
};
16491618
let zrtt_accepted = ZeroRttAccepted {
16501619
inner: zrtt_accepted,
@@ -1699,7 +1668,7 @@ impl Future for Connecting {
16991668
Poll::Ready(Ok(inner)) => {
17001669
let conn = Connection {
17011670
inner,
1702-
tls_auth: this.ep.static_config.tls_auth,
1671+
tls_auth: this.ep.static_config.tls_config.auth,
17031672
};
17041673
try_send_rtt_msg(&conn, this.ep, *this.remote_node_id);
17051674
Poll::Ready(Ok(conn))

iroh/src/magicsock.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3460,9 +3460,8 @@ mod tests {
34603460
secret_key: &SecretKey,
34613461
tls_auth: crate::tls::Authentication,
34623462
) -> ServerConfig {
3463-
let quic_server_config = tls_auth
3464-
.make_server_config(secret_key, vec![], false)
3465-
.expect("should generate valid config");
3463+
let quic_server_config = crate::tls::TlsConfig::new(tls_auth, secret_key.clone())
3464+
.make_server_config(vec![], false);
34663465
let mut server_config = ServerConfig::with_crypto(Arc::new(quic_server_config));
34673466
server_config.transport_config(Arc::new(quinn::TransportConfig::default()));
34683467
server_config
@@ -4042,8 +4041,8 @@ mod tests {
40424041
secret_key: SecretKey,
40434042
tls_auth: tls::Authentication,
40444043
) -> anyhow::Result<Handle> {
4045-
let quic_server_config =
4046-
tls_auth.make_server_config(&secret_key, vec![ALPN.to_vec()], true)?;
4044+
let quic_server_config = tls::TlsConfig::new(tls_auth, secret_key.clone())
4045+
.make_server_config(vec![ALPN.to_vec()], true);
40474046
let mut server_config = ServerConfig::with_crypto(Arc::new(quic_server_config));
40484047
server_config.transport_config(Arc::new(quinn::TransportConfig::default()));
40494048

@@ -4110,13 +4109,13 @@ mod tests {
41104109
) -> Result<quinn::Connection> {
41114110
let alpns = vec![ALPN.to_vec()];
41124111
let quic_client_config =
4113-
tls_auth.make_client_config(&ep_secret_key, node_id, alpns, None, true)?;
4112+
tls::TlsConfig::new(tls_auth, ep_secret_key.clone()).make_client_config(alpns, true);
41144113
let mut client_config = quinn::ClientConfig::new(Arc::new(quic_client_config));
41154114
client_config.transport_config(transport_config);
41164115
let connect = ep.connect_with(
41174116
client_config,
41184117
mapped_addr.private_socket_addr(),
4119-
"localhost",
4118+
&tls::name::encode(node_id),
41204119
)?;
41214120
let connection = connect.await?;
41224121
Ok(connection)

iroh/src/protocol.rs

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
//!
1313
//! let router = Router::builder(endpoint)
1414
//! .accept(b"/my/alpn", Echo)
15-
//! .spawn()
16-
//! .await?;
15+
//! .spawn();
1716
//! # Ok(())
1817
//! # }
1918
//!
@@ -78,8 +77,7 @@ use crate::{
7877
///
7978
/// let router = Router::builder(endpoint)
8079
/// // .accept(&ALPN, <something>)
81-
/// .spawn()
82-
/// .await?;
80+
/// .spawn();
8381
///
8482
/// // wait until the user wants to
8583
/// tokio::signal::ctrl_c().await?;
@@ -255,7 +253,7 @@ impl RouterBuilder {
255253
}
256254

257255
/// Spawns an accept loop and returns a handle to it encapsulated as the [`Router`].
258-
pub async fn spawn(self) -> Result<Router> {
256+
pub fn spawn(self) -> Router {
259257
// Update the endpoint with our alpns.
260258
let alpns = self
261259
.protocols
@@ -264,10 +262,7 @@ impl RouterBuilder {
264262
.collect::<Vec<_>>();
265263

266264
let protocols = Arc::new(self.protocols);
267-
if let Err(err) = self.endpoint.set_alpns(alpns) {
268-
shutdown(&self.endpoint, protocols.clone()).await;
269-
return Err(err);
270-
}
265+
self.endpoint.set_alpns(alpns);
271266

272267
let mut join_set = JoinSet::new();
273268
let endpoint = self.endpoint.clone();
@@ -333,11 +328,11 @@ impl RouterBuilder {
333328
let task = task::spawn(run_loop_fut);
334329
let task = AbortOnDropHandle::new(task);
335330

336-
Ok(Router {
331+
Router {
337332
endpoint: self.endpoint,
338333
task: Arc::new(Mutex::new(Some(task))),
339334
cancel_token: cancel,
340-
})
335+
}
341336
}
342337
}
343338

@@ -441,7 +436,7 @@ mod tests {
441436
#[tokio::test]
442437
async fn test_shutdown() -> Result<()> {
443438
let endpoint = Endpoint::builder().bind().await?;
444-
let router = Router::builder(endpoint.clone()).spawn().await?;
439+
let router = Router::builder(endpoint.clone()).spawn();
445440

446441
assert!(!router.is_shutdown());
447442
assert!(!endpoint.is_closed());
@@ -481,10 +476,7 @@ mod tests {
481476
let e1 = Endpoint::builder().bind().await?;
482477
// deny all access
483478
let proto = AccessLimit::new(Echo, |_node_id| false);
484-
let r1 = Router::builder(e1.clone())
485-
.accept(ECHO_ALPN, proto)
486-
.spawn()
487-
.await?;
479+
let r1 = Router::builder(e1.clone()).accept(ECHO_ALPN, proto).spawn();
488480

489481
let addr1 = r1.endpoint().node_addr().await?;
490482

0 commit comments

Comments
 (0)