tokio-rustls/tokio-rustls/tests/early-data.rs

162 lines
4.6 KiB
Rust
Raw Normal View History

2019-10-01 15:00:49 +00:00
#![cfg(feature = "early-data")]
use futures_util::{future, future::Future, ready};
[DRAFT] update `tokio-rustls` to `rustls` 0.20.x (#64) * update to rustls 0.20 Signed-off-by: Eliza Weisman <eliza@buoyant.io> * track simple renamings in rustls Signed-off-by: Eliza Weisman <eliza@buoyant.io> * use reader/writer methods Signed-off-by: Eliza Weisman <eliza@buoyant.io> * fix find and replace Signed-off-by: Eliza Weisman <eliza@buoyant.io> * use rustls-pemfile crate for pem file parsing Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update misc api breakage Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update client example with api changes Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update server example with new APIs Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update test_stream test Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update tests to use new APIs Signed-off-by: Eliza Weisman <eliza@buoyant.io> * rm unused imports Signed-off-by: Eliza Weisman <eliza@buoyant.io> * handle rustls `WouldBlock` on eof Signed-off-by: Eliza Weisman <eliza@buoyant.io> * expect rustls to return wouldblock in tests Signed-off-by: Eliza Weisman <eliza@buoyant.io> * i think this is *actually* the right EOF behavior Signed-off-by: Eliza Weisman <eliza@buoyant.io> * bump version Signed-off-by: Eliza Weisman <eliza@buoyant.io> * okay that seems to fix it Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update to track builder API changes Signed-off-by: Eliza Weisman <eliza@buoyant.io> * actually shutdown read side on close notify Signed-off-by: Eliza Weisman <eliza@buoyant.io> * Further updates to rustls 0.20 (#68) * Adapt to RootCertStore API changes * Handle UnexpectedEof errors * Rename would_block to io_pending * Try to make badssl test failures more verbose * Rebuild AsyncRead impl * Upgrade to current rustls * Revert to using assert!() * Update to rustls 0.20 * Forward rustls features Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
2021-09-28 17:01:37 +00:00
use rustls::RootCertStore;
use std::convert::TryFrom;
use std::io::{self, BufRead, BufReader, Cursor};
2019-10-01 15:00:49 +00:00
use std::net::SocketAddr;
use std::pin::Pin;
use std::process::{Child, Command, Stdio};
2019-10-01 15:00:49 +00:00
use std::sync::Arc;
use std::task::{Context, Poll};
2019-10-01 15:00:49 +00:00
use std::time::Duration;
2021-10-05 08:43:54 +00:00
use tokio::io::{split, AsyncRead, AsyncWriteExt, ReadBuf};
2019-10-01 15:00:49 +00:00
use tokio::net::TcpStream;
2021-10-05 08:43:54 +00:00
use tokio::sync::oneshot;
use tokio::time::sleep;
[DRAFT] update `tokio-rustls` to `rustls` 0.20.x (#64) * update to rustls 0.20 Signed-off-by: Eliza Weisman <eliza@buoyant.io> * track simple renamings in rustls Signed-off-by: Eliza Weisman <eliza@buoyant.io> * use reader/writer methods Signed-off-by: Eliza Weisman <eliza@buoyant.io> * fix find and replace Signed-off-by: Eliza Weisman <eliza@buoyant.io> * use rustls-pemfile crate for pem file parsing Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update misc api breakage Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update client example with api changes Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update server example with new APIs Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update test_stream test Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update tests to use new APIs Signed-off-by: Eliza Weisman <eliza@buoyant.io> * rm unused imports Signed-off-by: Eliza Weisman <eliza@buoyant.io> * handle rustls `WouldBlock` on eof Signed-off-by: Eliza Weisman <eliza@buoyant.io> * expect rustls to return wouldblock in tests Signed-off-by: Eliza Weisman <eliza@buoyant.io> * i think this is *actually* the right EOF behavior Signed-off-by: Eliza Weisman <eliza@buoyant.io> * bump version Signed-off-by: Eliza Weisman <eliza@buoyant.io> * okay that seems to fix it Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update to track builder API changes Signed-off-by: Eliza Weisman <eliza@buoyant.io> * actually shutdown read side on close notify Signed-off-by: Eliza Weisman <eliza@buoyant.io> * Further updates to rustls 0.20 (#68) * Adapt to RootCertStore API changes * Handle UnexpectedEof errors * Rename would_block to io_pending * Try to make badssl test failures more verbose * Rebuild AsyncRead impl * Upgrade to current rustls * Revert to using assert!() * Update to rustls 0.20 * Forward rustls features Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
2021-09-28 17:01:37 +00:00
use tokio_rustls::{
client::TlsStream,
rustls::{self, ClientConfig, OwnedTrustAnchor},
TlsConnector,
};
2019-10-01 15:00:49 +00:00
struct Read1<T>(T);
impl<T: AsyncRead + Unpin> Future for Read1<T> {
type Output = io::Result<()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut buf = [0];
2021-10-05 08:43:54 +00:00
let mut buf = ReadBuf::new(&mut buf);
2019-10-01 15:00:49 +00:00
ready!(Pin::new(&mut self.0).poll_read(cx, &mut buf))?;
2021-10-05 08:43:54 +00:00
if buf.filled().is_empty() {
Poll::Ready(Ok(()))
} else {
Poll::Pending
}
2019-10-01 15:00:49 +00:00
}
}
async fn send(
config: Arc<ClientConfig>,
addr: SocketAddr,
data: &[u8],
) -> io::Result<TlsStream<TcpStream>> {
let connector = TlsConnector::from(config).early_data(true);
2019-10-01 15:00:49 +00:00
let stream = TcpStream::connect(&addr).await?;
[DRAFT] update `tokio-rustls` to `rustls` 0.20.x (#64) * update to rustls 0.20 Signed-off-by: Eliza Weisman <eliza@buoyant.io> * track simple renamings in rustls Signed-off-by: Eliza Weisman <eliza@buoyant.io> * use reader/writer methods Signed-off-by: Eliza Weisman <eliza@buoyant.io> * fix find and replace Signed-off-by: Eliza Weisman <eliza@buoyant.io> * use rustls-pemfile crate for pem file parsing Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update misc api breakage Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update client example with api changes Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update server example with new APIs Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update test_stream test Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update tests to use new APIs Signed-off-by: Eliza Weisman <eliza@buoyant.io> * rm unused imports Signed-off-by: Eliza Weisman <eliza@buoyant.io> * handle rustls `WouldBlock` on eof Signed-off-by: Eliza Weisman <eliza@buoyant.io> * expect rustls to return wouldblock in tests Signed-off-by: Eliza Weisman <eliza@buoyant.io> * i think this is *actually* the right EOF behavior Signed-off-by: Eliza Weisman <eliza@buoyant.io> * bump version Signed-off-by: Eliza Weisman <eliza@buoyant.io> * okay that seems to fix it Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update to track builder API changes Signed-off-by: Eliza Weisman <eliza@buoyant.io> * actually shutdown read side on close notify Signed-off-by: Eliza Weisman <eliza@buoyant.io> * Further updates to rustls 0.20 (#68) * Adapt to RootCertStore API changes * Handle UnexpectedEof errors * Rename would_block to io_pending * Try to make badssl test failures more verbose * Rebuild AsyncRead impl * Upgrade to current rustls * Revert to using assert!() * Update to rustls 0.20 * Forward rustls features Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
2021-09-28 17:01:37 +00:00
let domain = rustls::ServerName::try_from("testserver.com").unwrap();
2019-10-01 15:00:49 +00:00
2021-10-05 08:43:54 +00:00
let stream = connector.connect(domain, stream).await?;
let (mut rd, mut wd) = split(stream);
let (notify, wait) = oneshot::channel();
let j = tokio::spawn(async move {
// read to eof
//
// see https://www.mail-archive.com/openssl-users@openssl.org/msg84451.html
let mut read_task = Read1(&mut rd);
let mut notify = Some(notify);
// read once, then write
//
// this is a regression test, see https://github.com/tokio-rs/tls/issues/54
future::poll_fn(|cx| {
let ret = Pin::new(&mut read_task).poll(cx)?;
assert_eq!(ret, Poll::Pending);
notify.take().unwrap().send(()).unwrap();
Poll::Ready(Ok(())) as Poll<io::Result<_>>
})
.await?;
match read_task.await {
Ok(()) => (),
Err(ref err) if err.kind() == io::ErrorKind::UnexpectedEof => (),
Err(err) => return Err(err.into()),
}
Ok(rd) as io::Result<_>
});
wait.await.unwrap();
2019-10-01 15:00:49 +00:00
2021-10-05 08:43:54 +00:00
wd.write_all(data).await?;
wd.flush().await?;
wd.shutdown().await?;
2019-10-01 15:00:49 +00:00
2021-10-05 08:43:54 +00:00
let rd: tokio::io::ReadHalf<_> = j.await??;
2019-10-01 15:00:49 +00:00
2021-10-05 08:43:54 +00:00
Ok(rd.unsplit(wd))
2019-10-01 15:00:49 +00:00
}
struct DropKill(Child);
impl Drop for DropKill {
fn drop(&mut self) {
self.0.kill().unwrap();
}
}
#[tokio::test]
async fn test_0rtt() -> io::Result<()> {
let mut handle = Command::new("openssl")
.arg("s_server")
.arg("-early_data")
.arg("-tls1_3")
.args(&["-cert", "./tests/end.cert"])
.args(&["-key", "./tests/end.rsa"])
.args(&["-port", "12354"])
2020-02-24 19:42:22 +00:00
.stdin(Stdio::piped())
2019-10-01 15:00:49 +00:00
.stdout(Stdio::piped())
.spawn()
.map(DropKill)?;
// wait openssl server
sleep(Duration::from_secs(1)).await;
2019-10-01 15:00:49 +00:00
let mut chain = BufReader::new(Cursor::new(include_str!("end.chain")));
[DRAFT] update `tokio-rustls` to `rustls` 0.20.x (#64) * update to rustls 0.20 Signed-off-by: Eliza Weisman <eliza@buoyant.io> * track simple renamings in rustls Signed-off-by: Eliza Weisman <eliza@buoyant.io> * use reader/writer methods Signed-off-by: Eliza Weisman <eliza@buoyant.io> * fix find and replace Signed-off-by: Eliza Weisman <eliza@buoyant.io> * use rustls-pemfile crate for pem file parsing Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update misc api breakage Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update client example with api changes Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update server example with new APIs Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update test_stream test Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update tests to use new APIs Signed-off-by: Eliza Weisman <eliza@buoyant.io> * rm unused imports Signed-off-by: Eliza Weisman <eliza@buoyant.io> * handle rustls `WouldBlock` on eof Signed-off-by: Eliza Weisman <eliza@buoyant.io> * expect rustls to return wouldblock in tests Signed-off-by: Eliza Weisman <eliza@buoyant.io> * i think this is *actually* the right EOF behavior Signed-off-by: Eliza Weisman <eliza@buoyant.io> * bump version Signed-off-by: Eliza Weisman <eliza@buoyant.io> * okay that seems to fix it Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update to track builder API changes Signed-off-by: Eliza Weisman <eliza@buoyant.io> * actually shutdown read side on close notify Signed-off-by: Eliza Weisman <eliza@buoyant.io> * Further updates to rustls 0.20 (#68) * Adapt to RootCertStore API changes * Handle UnexpectedEof errors * Rename would_block to io_pending * Try to make badssl test failures more verbose * Rebuild AsyncRead impl * Upgrade to current rustls * Revert to using assert!() * Update to rustls 0.20 * Forward rustls features Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
2021-09-28 17:01:37 +00:00
let certs = rustls_pemfile::certs(&mut chain).unwrap();
let trust_anchors = certs
.iter()
.map(|cert| {
let ta = webpki::TrustAnchor::try_from_cert_der(&cert[..]).unwrap();
OwnedTrustAnchor::from_subject_spki_name_constraints(
ta.subject,
ta.spki,
ta.name_constraints,
)
})
.collect::<Vec<_>>();
let mut root_store = RootCertStore::empty();
root_store.add_server_trust_anchors(trust_anchors.into_iter());
let mut config = rustls::ClientConfig::builder()
.with_safe_default_cipher_suites()
.with_safe_default_kx_groups()
.with_protocol_versions(&[&rustls::version::TLS13])
.unwrap()
.with_root_certificates(root_store)
.with_no_client_auth();
2019-10-01 15:00:49 +00:00
config.enable_early_data = true;
let config = Arc::new(config);
let addr = SocketAddr::from(([127, 0, 0, 1], 12354));
let io = send(config.clone(), addr, b"hello").await?;
assert!(!io.get_ref().1.is_early_data_accepted());
let io = send(config, addr, b"world!").await?;
assert!(io.get_ref().1.is_early_data_accepted());
let stdout = handle.0.stdout.as_mut().unwrap();
let mut lines = BufReader::new(stdout).lines();
let has_msg1 = lines.by_ref().any(|line| line.unwrap().contains("hello"));
let has_msg2 = lines.by_ref().any(|line| line.unwrap().contains("world!"));
2019-10-01 15:00:49 +00:00
2020-01-11 17:06:15 +00:00
assert!(has_msg1 && has_msg2);
2019-10-10 17:24:27 +00:00
2019-10-01 15:00:49 +00:00
Ok(())
}