tokio-xmpp: Support channel binding on TLS 1.3

This is defined in RFC 9266, and relies on the Exported Keying Material
to be passed to the SASL implementation.
This commit is contained in:
Emmanuel Gil Peyrot 2023-10-25 19:22:50 +02:00
parent b5aa36b72c
commit faabc2984a

View file

@ -1,5 +1,7 @@
use futures::{sink::SinkExt, Sink, Stream}; use futures::{sink::SinkExt, Sink, Stream};
use idna; use idna;
#[cfg(feature = "tls-native")]
use log::warn;
use sasl::common::{ChannelBinding, Credentials}; use sasl::common::{ChannelBinding, Credentials};
use std::pin::Pin; use std::pin::Pin;
use std::str::FromStr; use std::str::FromStr;
@ -8,7 +10,7 @@ use tokio::net::TcpStream;
#[cfg(feature = "tls-native")] #[cfg(feature = "tls-native")]
use tokio_native_tls::TlsStream; use tokio_native_tls::TlsStream;
#[cfg(all(feature = "tls-rust", not(feature = "tls-native")))] #[cfg(all(feature = "tls-rust", not(feature = "tls-native")))]
use tokio_rustls::client::TlsStream; use tokio_rustls::{client::TlsStream, rustls::ProtocolVersion};
use tokio_stream::StreamExt; use tokio_stream::StreamExt;
use xmpp_parsers::{ns, Element, Jid}; use xmpp_parsers::{ns, Element, Jid};
@ -62,9 +64,34 @@ impl Client {
xmpp_stream::XMPPStream::start(tcp_stream, jid.clone(), ns::JABBER_CLIENT.to_owned()) xmpp_stream::XMPPStream::start(tcp_stream, jid.clone(), ns::JABBER_CLIENT.to_owned())
.await?; .await?;
let channel_binding;
let xmpp_stream = if xmpp_stream.stream_features.can_starttls() { let xmpp_stream = if xmpp_stream.stream_features.can_starttls() {
// TlsStream // TlsStream
let tls_stream = starttls(xmpp_stream).await?; let tls_stream = starttls(xmpp_stream).await?;
#[cfg(feature = "tls-native")]
{
warn!("tls-native doesnt support channel binding, please use tls-rust if you want this feature!");
channel_binding = ChannelBinding::None;
}
#[cfg(all(feature = "tls-rust", not(feature = "tls-native")))]
{
let (_, connection) = tls_stream.get_ref();
match connection.protocol_version() {
// TODO: Add support for TLS 1.2 and earlier.
Some(ProtocolVersion::TLSv1_3) => {
let data = vec![0u8; 32];
let data = connection.export_keying_material(
data,
b"EXPORTER-Channel-Binding",
None,
)?;
channel_binding = ChannelBinding::TlsExporter(data);
}
_ => {
channel_binding = ChannelBinding::None;
}
}
}
// Encrypted XMPPStream // Encrypted XMPPStream
xmpp_stream::XMPPStream::start(tls_stream, jid.clone(), ns::JABBER_CLIENT.to_owned()) xmpp_stream::XMPPStream::start(tls_stream, jid.clone(), ns::JABBER_CLIENT.to_owned())
.await? .await?
@ -75,7 +102,7 @@ impl Client {
let creds = Credentials::default() let creds = Credentials::default()
.with_username(username) .with_username(username)
.with_password(password) .with_password(password)
.with_channel_binding(ChannelBinding::None); .with_channel_binding(channel_binding);
// Authenticated (unspecified) stream // Authenticated (unspecified) stream
let stream = auth(xmpp_stream, creds).await?; let stream = auth(xmpp_stream, creds).await?;
// Authenticated XMPPStream // Authenticated XMPPStream