Skip to main content

wasmtime_wasi_tls/providers/
rustls.rs

1//! The `rustls` provider.
2
3use crate::{BoxFutureTlsStream, Error, TlsProvider, TlsStream, TlsTransport};
4use rustls::pki_types::ServerName;
5use std::sync::{Arc, LazyLock};
6
7impl crate::TlsStream for tokio_rustls::client::TlsStream<Box<dyn TlsTransport>> {}
8
9/// The `rustls` provider.
10pub struct RustlsProvider {
11    client_config: Arc<rustls::ClientConfig>,
12}
13
14impl TlsProvider for RustlsProvider {
15    fn connect(&self, server_name: String, transport: Box<dyn TlsTransport>) -> BoxFutureTlsStream {
16        let client_config = Arc::clone(&self.client_config);
17        Box::pin(async move {
18            let domain =
19                ServerName::try_from(server_name).map_err(|_| Error::msg("invalid server name"))?;
20
21            let stream = tokio_rustls::TlsConnector::from(client_config)
22                .connect(domain, transport)
23                .await
24                .map_err(rustls_to_wasi_error)?;
25            Ok(Box::new(stream) as Box<dyn TlsStream>)
26        })
27    }
28}
29
30impl Default for RustlsProvider {
31    fn default() -> Self {
32        static CONFIG: LazyLock<Arc<rustls::ClientConfig>> = LazyLock::new(|| {
33            let roots = rustls::RootCertStore {
34                roots: webpki_roots::TLS_SERVER_ROOTS.into(),
35            };
36            let config = rustls::ClientConfig::builder()
37                .with_root_certificates(roots)
38                .with_no_client_auth();
39            Arc::new(config)
40        });
41
42        Self {
43            client_config: Arc::clone(&CONFIG),
44        }
45    }
46}
47
48impl From<rustls::Error> for Error {
49    fn from(e: rustls::Error) -> Self {
50        Error::msg(e.to_string())
51    }
52}
53
54fn rustls_to_wasi_error(e: std::io::Error) -> Error {
55    match e.downcast::<rustls::Error>() {
56        Ok(e) => e.into(),
57        Err(io_err) => Error::msg(io_err),
58    }
59}