From 5714c3c8ccbffb554ff43be29df194d7c6514d02 Mon Sep 17 00:00:00 2001 From: James Mayclin Date: Tue, 19 Nov 2024 20:54:05 -0800 Subject: [PATCH] test(s2n-tls-hyper): matching on s2n-tls error (#4906) --- .../rust/s2n-tls-hyper/tests/common/echo.rs | 2 +- .../rust/s2n-tls-hyper/tests/common/mod.rs | 5 +- bindings/rust/s2n-tls-hyper/tests/http.rs | 77 +++++++++++++++++++ 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/bindings/rust/s2n-tls-hyper/tests/common/echo.rs b/bindings/rust/s2n-tls-hyper/tests/common/echo.rs index 044a99d775d..36ce865ca7d 100644 --- a/bindings/rust/s2n-tls-hyper/tests/common/echo.rs +++ b/bindings/rust/s2n-tls-hyper/tests/common/echo.rs @@ -17,7 +17,7 @@ async fn echo( Ok(Response::new(req.into_body().boxed())) } -async fn serve_echo( +pub async fn serve_echo( tcp_listener: TcpListener, builder: B, ) -> Result<(), Box> diff --git a/bindings/rust/s2n-tls-hyper/tests/common/mod.rs b/bindings/rust/s2n-tls-hyper/tests/common/mod.rs index 148462d2d12..2da6cdace69 100644 --- a/bindings/rust/s2n-tls-hyper/tests/common/mod.rs +++ b/bindings/rust/s2n-tls-hyper/tests/common/mod.rs @@ -6,10 +6,9 @@ use s2n_tls::{callbacks::VerifyHostNameCallback, config, error::Error, security: pub mod echo; /// NOTE: this certificate and key are used for testing purposes only! -pub static CERT_PEM: &[u8] = +pub const CERT_PEM: &[u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/../certs/cert.pem")); -pub static KEY_PEM: &[u8] = - include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/../certs/key.pem")); +pub const KEY_PEM: &[u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/../certs/key.pem")); pub fn config() -> Result { let mut builder = config::Config::builder(); diff --git a/bindings/rust/s2n-tls-hyper/tests/http.rs b/bindings/rust/s2n-tls-hyper/tests/http.rs index 0a5469b45de..8a1a8a37243 100644 --- a/bindings/rust/s2n-tls-hyper/tests/http.rs +++ b/bindings/rust/s2n-tls-hyper/tests/http.rs @@ -3,15 +3,19 @@ use crate::common::InsecureAcceptAllCertificatesHandler; use bytes::Bytes; +use common::echo::serve_echo; use http::{Method, Request, Uri}; use http_body_util::{BodyExt, Empty, Full}; use hyper_util::{client::legacy::Client, rt::TokioExecutor}; use s2n_tls::{ callbacks::{ClientHelloCallback, ConnectionFuture}, + config, connection::Connection, + security::DEFAULT_TLS13, }; use s2n_tls_hyper::connector::HttpsConnector; use std::{error::Error, pin::Pin, str::FromStr}; +use tokio::{net::TcpListener, task::JoinHandle}; pub mod common; @@ -138,3 +142,76 @@ async fn test_sni() -> Result<(), Box> { Ok(()) } + +/// This test covers the general customer TLS Error experience. We want to +/// confirm that s2n-tls errors are correctly bubbled up and that details can be +/// extracted/matched on. +#[tokio::test] +async fn error_matching() -> Result<(), Box> { + let (server_task, addr) = { + let listener = TcpListener::bind("127.0.0.1:0").await?; + let addr = listener.local_addr()?; + let server_task = tokio::spawn(serve_echo(listener, common::config()?.build()?)); + (server_task, addr) + }; + + let client_task: JoinHandle>> = + tokio::spawn(async move { + // the client config won't trust the self-signed cert that the server + // uses. + let client_config = { + let mut builder = config::Config::builder(); + builder.set_security_policy(&DEFAULT_TLS13)?; + builder.set_max_blinding_delay(0)?; + builder.build()? + }; + + let connector = HttpsConnector::new(client_config); + let client: Client<_, Empty> = + Client::builder(TokioExecutor::new()).build(connector); + + let uri = Uri::from_str(format!("https://localhost:{}", addr.port()).as_str())?; + client.get(uri).await?; + + panic!("the client request should fail"); + }); + + // expected error: + // hyper_util::client::legacy::Error( + // Connect, + // TlsError( + // Error { + // code: 335544366, + // name: "S2N_ERR_CERT_UNTRUSTED", + // message: "Certificate is untrusted", + // kind: ProtocolError, + // source: Library, + // debug: "Error encountered in lib/tls/s2n_x509_validator.c:721", + // errno: "No such file or directory", + // }, + // ), + // ) + let client_response = client_task.await?; + let client_error = client_response.unwrap_err(); + let hyper_error: &hyper_util::client::legacy::Error = client_error.downcast_ref().unwrap(); + + // the error happened when attempting to connect to the endpoint. + assert!(hyper_error.is_connect()); + + let error_source = hyper_error.source().unwrap(); + let s2n_tls_hyper_error: &s2n_tls_hyper::error::Error = error_source.downcast_ref().unwrap(); + + let s2n_tls_error = match s2n_tls_hyper_error { + s2n_tls_hyper::error::Error::TlsError(s2n_tls_error) => s2n_tls_error, + _ => panic!("unexpected error type"), + }; + + assert_eq!( + s2n_tls_error.kind(), + s2n_tls::error::ErrorType::ProtocolError + ); + assert_eq!(s2n_tls_error.name(), "S2N_ERR_CERT_UNTRUSTED"); + + server_task.abort(); + Ok(()) +}