Avoid enabling multiple rustls backends by accident

For this, we had to:

- Make the choice(s) of backend explicit in tokio-xmpp features
- Avoid picking a backend through transitive dependencies in xmpp
  (reqwest->hyper->rustls).

In addition, we choose the default rustls backend by default and adapt
the examples so that they can cope with either situation.
This commit is contained in:
Jonas Schäfer 2025-05-10 09:54:01 +02:00
commit 4e9e18444c
11 changed files with 134 additions and 15 deletions

View file

@ -33,7 +33,7 @@ hickory-resolver = { version = "0.24", optional = true}
idna = { version = "1.0", optional = true} idna = { version = "1.0", optional = true}
native-tls = { version = "0.2", optional = true } native-tls = { version = "0.2", optional = true }
tokio-native-tls = { version = "0.3", optional = true } tokio-native-tls = { version = "0.3", optional = true }
tokio-rustls = { version = "0.26", optional = true } tokio-rustls = { version = "0.26", optional = true, default-features = false, features = ["logging", "tls12"] }
ktls = { version = "6", optional = true } ktls = { version = "6", optional = true }
[dev-dependencies] [dev-dependencies]
@ -43,9 +43,11 @@ tokio = { version = "1", features = ["signal", "test-util"] }
tokio-xmpp = { path = ".", features = ["insecure-tcp"]} tokio-xmpp = { path = ".", features = ["insecure-tcp"]}
[features] [features]
default = ["starttls-rust", "rustls-native-certs"] default = ["starttls-rust", "rustls-native-certs", "tls-rust-aws_lc_rs"]
starttls = ["dns"] starttls = ["dns"]
tls-rust = ["tokio-rustls"] tls-rust = ["tokio-rustls"]
tls-rust-aws_lc_rs = ["tokio-rustls?/aws_lc_rs"]
tls-rust-ring = ["tokio-rustls?/ring"]
tls-rust-ktls = ["tls-rust", "ktls"] tls-rust-ktls = ["tls-rust", "ktls"]
tls-rust-native-certs = ["tls-rust", "rustls-native-certs"] tls-rust-native-certs = ["tls-rust", "rustls-native-certs"]
tls-rust-webpki-roots = ["tls-rust", "webpki-roots"] tls-rust-webpki-roots = ["tls-rust", "webpki-roots"]

View file

@ -25,6 +25,13 @@ XXXX-YY-ZZ RELEASER <admin@example.com>
- `Component` is now gated behind `insecure-tcp` feature flag - `Component` is now gated behind `insecure-tcp` feature flag
- `XMPPStream` and `XmppCodec` were removed in favour of the newly - `XMPPStream` and `XmppCodec` were removed in favour of the newly
implemented `tokio_xmpp::xmlstream module. implemented `tokio_xmpp::xmlstream module.
- The `starttls-rust`, `tls-rust` and `tls-rust-ktls` feature flags do
not automatically enable a `rustls` crypto provider anymore. This is
to avoid conflict between two crypto providers and to avoid linking
unnecessary code. The `aws_lc_rs` crypto provider is still built by
default, however, applications which use `tokio_xmpp` without default
features will have to adapt their feature flags to explicitly enable
the `tls-rust-aws_lc_rs` or `tls-rust-ring` features. (!581)
* Added: * Added:
- Support for sending IQ requests while tracking their responses in a - Support for sending IQ requests while tracking their responses in a
Future. Future.

View file

@ -2,7 +2,12 @@ use futures::stream::StreamExt;
use std::env::args; use std::env::args;
use std::process::exit; use std::process::exit;
use std::str::FromStr; use std::str::FromStr;
use tokio_xmpp::{rustls, Client, IqRequest, IqResponse}; #[cfg(all(
feature = "tls-rust",
any(feature = "tls-rust-aws_lc_rs", feature = "tls-rust-ring")
))]
use tokio_xmpp::rustls;
use tokio_xmpp::{Client, IqRequest, IqResponse};
use xmpp_parsers::{ use xmpp_parsers::{
disco::{DiscoInfoQuery, DiscoInfoResult}, disco::{DiscoInfoQuery, DiscoInfoResult},
jid::{BareJid, Jid}, jid::{BareJid, Jid},
@ -14,11 +19,20 @@ use xmpp_parsers::{
async fn main() { async fn main() {
env_logger::init(); env_logger::init();
#[cfg(feature = "tls-rust")] #[cfg(all(feature = "tls-rust", feature = "tls-rust-aws_lc_rs"))]
rustls::crypto::aws_lc_rs::default_provider() rustls::crypto::aws_lc_rs::default_provider()
.install_default() .install_default()
.expect("failed to install rustls crypto provider"); .expect("failed to install rustls crypto provider");
#[cfg(all(
feature = "tls-rust",
feature = "tls-rust-ring",
not(feature = "tls-rust-aws_lc_rs")
))]
rustls::crypto::ring::default_provider()
.install_default()
.expect("failed to install rustls crypto provider");
let args: Vec<String> = args().collect(); let args: Vec<String> = args().collect();
if args.len() != 4 { if args.len() != 4 {
println!("Usage: {} <jid> <password> <target>", args[0]); println!("Usage: {} <jid> <password> <target>", args[0]);

View file

@ -4,7 +4,12 @@ use std::fs::{create_dir_all, File};
use std::io::{self, Write}; use std::io::{self, Write};
use std::process::exit; use std::process::exit;
use std::str::FromStr; use std::str::FromStr;
use tokio_xmpp::{rustls, Client, Stanza}; #[cfg(all(
feature = "tls-rust",
any(feature = "tls-rust-aws_lc_rs", feature = "tls-rust-ring")
))]
use tokio_xmpp::rustls;
use tokio_xmpp::{Client, Stanza};
use xmpp_parsers::{ use xmpp_parsers::{
avatar::{Data as AvatarData, Metadata as AvatarMetadata}, avatar::{Data as AvatarData, Metadata as AvatarMetadata},
caps::{compute_disco, hash_caps, Caps}, caps::{compute_disco, hash_caps, Caps},
@ -26,11 +31,20 @@ use xmpp_parsers::{
async fn main() { async fn main() {
env_logger::init(); env_logger::init();
#[cfg(feature = "tls-rust")] #[cfg(all(feature = "tls-rust", feature = "tls-rust-aws_lc_rs"))]
rustls::crypto::aws_lc_rs::default_provider() rustls::crypto::aws_lc_rs::default_provider()
.install_default() .install_default()
.expect("failed to install rustls crypto provider"); .expect("failed to install rustls crypto provider");
#[cfg(all(
feature = "tls-rust",
feature = "tls-rust-ring",
not(feature = "tls-rust-aws_lc_rs")
))]
rustls::crypto::ring::default_provider()
.install_default()
.expect("failed to install rustls crypto provider");
let args: Vec<String> = args().collect(); let args: Vec<String> = args().collect();
if args.len() != 3 { if args.len() != 3 {
println!("Usage: {} <jid> <password>", args[0]); println!("Usage: {} <jid> <password>", args[0]);

View file

@ -2,7 +2,12 @@ use futures::stream::StreamExt;
use std::env::args; use std::env::args;
use std::process::exit; use std::process::exit;
use std::str::FromStr; use std::str::FromStr;
use tokio_xmpp::{rustls, Client}; #[cfg(all(
feature = "tls-rust",
any(feature = "tls-rust-aws_lc_rs", feature = "tls-rust-ring")
))]
use tokio_xmpp::rustls;
use tokio_xmpp::Client;
use xmpp_parsers::jid::{BareJid, Jid}; use xmpp_parsers::jid::{BareJid, Jid};
use xmpp_parsers::message::{Lang, Message, MessageType}; use xmpp_parsers::message::{Lang, Message, MessageType};
use xmpp_parsers::presence::{Presence, Show as PresenceShow, Type as PresenceType}; use xmpp_parsers::presence::{Presence, Show as PresenceShow, Type as PresenceType};
@ -11,11 +16,20 @@ use xmpp_parsers::presence::{Presence, Show as PresenceShow, Type as PresenceTyp
async fn main() { async fn main() {
env_logger::init(); env_logger::init();
#[cfg(feature = "tls-rust")] #[cfg(all(feature = "tls-rust", feature = "tls-rust-aws_lc_rs"))]
rustls::crypto::aws_lc_rs::default_provider() rustls::crypto::aws_lc_rs::default_provider()
.install_default() .install_default()
.expect("failed to install rustls crypto provider"); .expect("failed to install rustls crypto provider");
#[cfg(all(
feature = "tls-rust",
feature = "tls-rust-ring",
not(feature = "tls-rust-aws_lc_rs")
))]
rustls::crypto::ring::default_provider()
.install_default()
.expect("failed to install rustls crypto provider");
let args: Vec<String> = args().collect(); let args: Vec<String> = args().collect();
if args.len() != 3 { if args.len() != 3 {
println!("Usage: {} <jid> <password>", args[0]); println!("Usage: {} <jid> <password>", args[0]);

View file

@ -6,17 +6,31 @@ use xmpp_parsers::jid::Jid;
use xmpp_parsers::message::{Lang, Message, MessageType}; use xmpp_parsers::message::{Lang, Message, MessageType};
use xmpp_parsers::presence::{Presence, Show as PresenceShow, Type as PresenceType}; use xmpp_parsers::presence::{Presence, Show as PresenceShow, Type as PresenceType};
use tokio_xmpp::{connect::DnsConfig, rustls, Component}; #[cfg(all(
feature = "tls-rust",
any(feature = "tls-rust-aws_lc_rs", feature = "tls-rust-ring")
))]
use tokio_xmpp::rustls;
use tokio_xmpp::{connect::DnsConfig, Component};
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
env_logger::init(); env_logger::init();
#[cfg(feature = "tls-rust")] #[cfg(all(feature = "tls-rust", feature = "tls-rust-aws_lc_rs"))]
rustls::crypto::aws_lc_rs::default_provider() rustls::crypto::aws_lc_rs::default_provider()
.install_default() .install_default()
.expect("failed to install rustls crypto provider"); .expect("failed to install rustls crypto provider");
#[cfg(all(
feature = "tls-rust",
feature = "tls-rust-ring",
not(feature = "tls-rust-aws_lc_rs")
))]
rustls::crypto::ring::default_provider()
.install_default()
.expect("failed to install rustls crypto provider");
let args: Vec<String> = args().collect(); let args: Vec<String> = args().collect();
if args.len() < 3 || args.len() > 4 { if args.len() < 3 || args.len() > 4 {
println!("Usage: {} <jid> <password> [server:port]", args[0]); println!("Usage: {} <jid> <password> [server:port]", args[0]);

View file

@ -1,20 +1,33 @@
use futures::{SinkExt, StreamExt}; use futures::{SinkExt, StreamExt};
use tokio::{self, io, net::TcpSocket}; use tokio::{self, io, net::TcpSocket};
#[cfg(all(
feature = "tls-rust",
any(feature = "tls-rust-aws_lc_rs", feature = "tls-rust-ring")
))]
use tokio_xmpp::rustls;
use tokio_xmpp::{ use tokio_xmpp::{
minidom::Element, minidom::Element,
parsers::stream_features::StreamFeatures, parsers::stream_features::StreamFeatures,
rustls,
xmlstream::{accept_stream, StreamHeader, Timeouts}, xmlstream::{accept_stream, StreamHeader, Timeouts},
}; };
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), io::Error> { async fn main() -> Result<(), io::Error> {
#[cfg(feature = "tls-rust")] #[cfg(all(feature = "tls-rust", feature = "tls-rust-aws_lc_rs"))]
rustls::crypto::aws_lc_rs::default_provider() rustls::crypto::aws_lc_rs::default_provider()
.install_default() .install_default()
.expect("failed to install rustls crypto provider"); .expect("failed to install rustls crypto provider");
#[cfg(all(
feature = "tls-rust",
feature = "tls-rust-ring",
not(feature = "tls-rust-aws_lc_rs")
))]
rustls::crypto::ring::default_provider()
.install_default()
.expect("failed to install rustls crypto provider");
// TCP socket // TCP socket
let address = "127.0.0.1:5222".parse().unwrap(); let address = "127.0.0.1:5222".parse().unwrap();
let socket = TcpSocket::new_v4()?; let socket = TcpSocket::new_v4()?;

View file

@ -19,6 +19,11 @@ use rand::{thread_rng, Rng};
use futures::StreamExt; use futures::StreamExt;
#[cfg(all(
feature = "tls-rust",
any(feature = "tls-rust-aws_lc_rs", feature = "tls-rust-ring")
))]
use tokio_xmpp::rustls;
use tokio_xmpp::{ use tokio_xmpp::{
connect::{DnsConfig, StartTlsServerConnector}, connect::{DnsConfig, StartTlsServerConnector},
parsers::{ parsers::{
@ -26,7 +31,6 @@ use tokio_xmpp::{
jid::{BareJid, Jid}, jid::{BareJid, Jid},
ping, ping,
}, },
rustls,
stanzastream::StanzaStream, stanzastream::StanzaStream,
xmlstream::Timeouts, xmlstream::Timeouts,
}; };
@ -35,11 +39,20 @@ use tokio_xmpp::{
async fn main() { async fn main() {
env_logger::init(); env_logger::init();
#[cfg(feature = "tls-rust")] #[cfg(all(feature = "tls-rust", feature = "tls-rust-aws_lc_rs"))]
rustls::crypto::aws_lc_rs::default_provider() rustls::crypto::aws_lc_rs::default_provider()
.install_default() .install_default()
.expect("failed to install rustls crypto provider"); .expect("failed to install rustls crypto provider");
#[cfg(all(
feature = "tls-rust",
feature = "tls-rust-ring",
not(feature = "tls-rust-aws_lc_rs")
))]
rustls::crypto::ring::default_provider()
.install_default()
.expect("failed to install rustls crypto provider");
let args: Vec<String> = args().collect(); let args: Vec<String> = args().collect();
if args.len() != 3 { if args.len() != 3 {
println!("Usage: {} <jid> <password>", args[0]); println!("Usage: {} <jid> <password>", args[0]);

View file

@ -33,7 +33,9 @@ required-features = ["avatars"]
[features] [features]
default = ["avatars", "starttls-rust"] default = ["avatars", "starttls-rust"]
starttls-native = ["tokio-xmpp/starttls", "tokio-xmpp/tls-native", "reqwest/native-tls"] starttls-native = ["tokio-xmpp/starttls", "tokio-xmpp/tls-native", "reqwest/native-tls"]
starttls-rust = ["tokio-xmpp/starttls", "tokio-xmpp/tls-rust", "reqwest/rustls-tls"] starttls-rust = ["tokio-xmpp/starttls", "tokio-xmpp/tls-rust", "reqwest/rustls-tls-no-provider", "tokio-xmpp/tls-rust-webpki-roots"]
starttls-rust-aws_lc_rs = ["tokio-xmpp/tls-rust-aws_lc_rs", "starttls-rust"]
starttls-rust-ring = ["tokio-xmpp/tls-rust-ring", "starttls-rust"]
avatars = [] avatars = []
escape-hatch = [] escape-hatch = []
syntax-highlighting = [ "tokio-xmpp/syntax-highlighting" ] syntax-highlighting = [ "tokio-xmpp/syntax-highlighting" ]

View file

@ -15,6 +15,13 @@ XXXX-YY-ZZ [ RELEASER <admin@localhost> ]
- Agent::send_room_private_message now takes RoomPrivateMessageSettings (!487) - Agent::send_room_private_message now takes RoomPrivateMessageSettings (!487)
- Event now exposes Option<MessageId> for incoming messages, and MessageId - Event now exposes Option<MessageId> for incoming messages, and MessageId
for incoming message corrections; type alias Id has been removed (!504) for incoming message corrections; type alias Id has been removed (!504)
- The `starttls-rust` feature flag does not automatically enable a
`rustls` crypto provider anymore. This is to avoid conflict between
two crypto providers and to avoid linking unnecessary code. The
`aws_lc_rs` crypto provider is still built by default, however,
applications which use `xmpp` without default features will have to
adapt their feature flags to explicitly enable the
`starttls-rust-aws_lc_rs` or `starttls-rust-ring` features. (!581)
* Added: * Added:
- Agent::send_room_message takes RoomMessageSettings argument (!483) - Agent::send_room_message takes RoomMessageSettings argument (!483)
- Agent::send_raw_message takes RawMessageSettings for any message type (!487) - Agent::send_raw_message takes RawMessageSettings for any message type (!487)

View file

@ -4,6 +4,11 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
#[cfg(all(
feature = "starttls-rust",
any(feature = "starttls-rust-aws_lc_rs", feature = "starttls-rust-ring")
))]
use xmpp::tokio_xmpp::rustls;
use xmpp::{ use xmpp::{
jid::BareJid, jid::BareJid,
muc::room::{JoinRoomSettings, RoomMessageSettings}, muc::room::{JoinRoomSettings, RoomMessageSettings},
@ -19,6 +24,20 @@ use std::str::FromStr;
async fn main() -> Result<(), Option<()>> { async fn main() -> Result<(), Option<()>> {
env_logger::init(); env_logger::init();
#[cfg(all(feature = "starttls-rust", feature = "starttls-rust-aws_lc_rs"))]
rustls::crypto::aws_lc_rs::default_provider()
.install_default()
.expect("failed to install rustls crypto provider");
#[cfg(all(
feature = "starttls-rust",
feature = "starttls-rust-ring",
not(feature = "starttls-rust-aws_lc_rs")
))]
rustls::crypto::ring::default_provider()
.install_default()
.expect("failed to install rustls crypto provider");
let args: Vec<String> = args().collect(); let args: Vec<String> = args().collect();
if args.len() < 3 { if args.len() < 3 {
println!("Usage: {} <jid> <password> [ROOM...]", args[0]); println!("Usage: {} <jid> <password> [ROOM...]", args[0]);