1 //! # Wasmtime's [wasi-tls] (Transport Layer Security) Implementation 2 //! 3 //! This crate provides the Wasmtime host implementation for the [wasi-tls] API. 4 //! The [wasi-tls] world allows WebAssembly modules to perform SSL/TLS operations, 5 //! such as establishing secure connections to servers. TLS often relies on other wasi networking systems 6 //! to provide the stream so it will be common to enable the [wasi:cli] world as well with the networking features enabled. 7 //! 8 //! # An example of how to configure [wasi-tls] is the following: 9 //! 10 //! ```rust 11 //! use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView}; 12 //! use wasmtime::{ 13 //! component::{Linker, ResourceTable}, 14 //! Store, Engine, Result, 15 //! }; 16 //! use wasmtime_wasi_tls::{WasiTlsCtx, WasiTlsCtxBuilder, WasiTlsView, WasiTlsCtxView}; 17 //! use wasmtime_wasi_tls::p2::LinkOptions; 18 //! 19 //! struct Ctx { 20 //! table: ResourceTable, 21 //! wasi_ctx: WasiCtx, 22 //! wasi_tls_ctx: WasiTlsCtx, 23 //! } 24 //! 25 //! impl WasiView for Ctx { 26 //! fn ctx(&mut self) -> WasiCtxView<'_> { 27 //! WasiCtxView { ctx: &mut self.wasi_ctx, table: &mut self.table } 28 //! } 29 //! } 30 //! 31 //! impl WasiTlsView for Ctx { 32 //! fn tls(&mut self) -> WasiTlsCtxView<'_> { 33 //! WasiTlsCtxView { ctx: &mut self.wasi_tls_ctx, table: &mut self.table } 34 //! } 35 //! } 36 //! 37 //! #[tokio::main] 38 //! async fn main() -> Result<()> { 39 //! let ctx = Ctx { 40 //! table: ResourceTable::new(), 41 //! wasi_ctx: WasiCtx::builder() 42 //! .inherit_stderr() 43 //! .inherit_network() 44 //! .allow_ip_name_lookup(true) 45 //! .build(), 46 //! wasi_tls_ctx: WasiTlsCtxBuilder::new() 47 //! // Optionally, configure a specific TLS provider: 48 //! // .provider(Box::new(wasmtime_wasi_tls::RustlsProvider::default())) 49 //! // .provider(Box::new(wasmtime_wasi_tls::NativeTlsProvider::default())) 50 //! // .provider(Box::new(wasmtime_wasi_tls::OpenSslProvider::default())) 51 //! .build(), 52 //! }; 53 //! 54 //! let engine = Engine::default(); 55 //! 56 //! // Set up wasi-cli 57 //! let mut store = Store::new(&engine, ctx); 58 //! let mut linker: Linker<Ctx> = Linker::new(&engine); 59 //! wasmtime_wasi::p2::add_to_linker_async(&mut linker)?; 60 //! 61 //! // Add wasi-tls types and turn on the feature in linker 62 //! let mut opts = LinkOptions::default(); 63 //! opts.tls(true); 64 //! wasmtime_wasi_tls::p2::add_to_linker(&mut linker, &opts)?; 65 //! 66 //! // ... use `linker` to instantiate within `store` ... 67 //! Ok(()) 68 //! } 69 //! 70 //! ``` 71 //! [wasi-tls]: https://github.com/WebAssembly/wasi-tls 72 //! [wasi:cli]: https://docs.rs/wasmtime-wasi/latest 73 74 #![deny(missing_docs)] 75 #![doc(test(attr(deny(warnings))))] 76 #![doc(test(attr(allow(dead_code, unused_variables, unused_mut))))] 77 78 use tokio::io::{AsyncRead, AsyncWrite}; 79 mod error; 80 mod providers; 81 82 /// WASIp2 (`wasi:[email protected]`) host implementation. 83 #[cfg(feature = "p2")] 84 pub mod p2; 85 /// WASIp3 (`wasi:[email protected]`) host implementation. 86 #[cfg(feature = "p3")] 87 pub mod p3; 88 89 pub use error::Error; 90 pub use providers::*; 91 92 #[cfg(any(feature = "p2", feature = "p3"))] 93 use wasmtime::component::{HasData, ResourceTable}; 94 95 /// Builder-style structure used to create a [`WasiTlsCtx`]. 96 #[cfg(any(feature = "p2", feature = "p3"))] 97 pub struct WasiTlsCtxBuilder { 98 provider: Box<dyn TlsProvider>, 99 } 100 #[cfg(any(feature = "p2", feature = "p3"))] 101 impl WasiTlsCtxBuilder { 102 /// Creates a builder for a new context with default parameters set. new() -> Self103 pub fn new() -> Self { 104 Default::default() 105 } 106 107 /// Configure the TLS provider to use for this context. 108 /// 109 /// By default, this is set to the [`DefaultProvider`] which is picked at 110 /// compile time based on feature flags. If this crate is compiled with 111 /// multiple TLS providers, this method can be used to specify the provider 112 /// at runtime. provider(mut self, provider: Box<dyn TlsProvider>) -> Self113 pub fn provider(mut self, provider: Box<dyn TlsProvider>) -> Self { 114 self.provider = provider; 115 self 116 } 117 118 /// Uses the configured context so far to construct the final [`WasiTlsCtx`]. build(self) -> WasiTlsCtx119 pub fn build(self) -> WasiTlsCtx { 120 WasiTlsCtx { 121 provider: self.provider, 122 } 123 } 124 } 125 #[cfg(any(feature = "p2", feature = "p3"))] 126 impl Default for WasiTlsCtxBuilder { default() -> Self127 fn default() -> Self { 128 Self { 129 provider: Box::new(DefaultProvider::default()), 130 } 131 } 132 } 133 134 /// Wasi TLS context needed for internal `wasi-tls` state. 135 #[cfg(any(feature = "p2", feature = "p3"))] 136 pub struct WasiTlsCtx { 137 pub(crate) provider: Box<dyn TlsProvider>, 138 } 139 140 /// The type for which this crate implements the `wasi:tls` interfaces. 141 #[cfg(any(feature = "p2", feature = "p3"))] 142 pub(crate) struct WasiTls; 143 #[cfg(any(feature = "p2", feature = "p3"))] 144 impl HasData for WasiTls { 145 type Data<'a> = WasiTlsCtxView<'a>; 146 } 147 148 /// View into [`WasiTlsCtx`] implementation and [`ResourceTable`]. 149 #[cfg(any(feature = "p2", feature = "p3"))] 150 pub struct WasiTlsCtxView<'a> { 151 /// Mutable reference to table used to manage resources. 152 pub table: &'a mut ResourceTable, 153 154 /// Mutable reference to the WASI TLS context. 155 pub ctx: &'a mut WasiTlsCtx, 156 } 157 158 /// A trait which provides internal WASI TLS state. 159 #[cfg(any(feature = "p2", feature = "p3"))] 160 pub trait WasiTlsView: Send { 161 /// Return a [`WasiTlsCtxView`] from mutable reference to self. tls(&mut self) -> WasiTlsCtxView<'_>162 fn tls(&mut self) -> WasiTlsCtxView<'_>; 163 } 164 165 /// The data stream that carries the encrypted TLS data. 166 /// Typically this is a TCP stream. 167 pub trait TlsTransport: AsyncRead + AsyncWrite + Send + Unpin + 'static {} 168 impl<T: AsyncRead + AsyncWrite + Send + Unpin + ?Sized + 'static> TlsTransport for T {} 169 170 /// A TLS connection. 171 pub trait TlsStream: AsyncRead + AsyncWrite + Send + Unpin + 'static {} 172 173 /// A TLS implementation. 174 pub trait TlsProvider: Send + Sync + 'static { 175 /// Set up a client TLS connection using the provided `server_name` and `transport`. connect(&self, server_name: String, transport: Box<dyn TlsTransport>) -> BoxFutureTlsStream176 fn connect(&self, server_name: String, transport: Box<dyn TlsTransport>) -> BoxFutureTlsStream; 177 } 178 179 pub(crate) type BoxFutureTlsStream = 180 std::pin::Pin<Box<dyn Future<Output = Result<Box<dyn TlsStream>, Error>> + Send>>; 181