Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -932,10 +932,17 @@ jobs:
# Run the tests!
- run: cargo test -p wasmtime-wasi-nn --features ${{ matrix.feature }}

# Test `wasmtime-wasi-tls-nativetls` in its own job. This is because it
# depends on OpenSSL, which is not easily available on all platforms.
test_wasi_tls_nativetls:
name: Test wasi-tls using native-tls provider
# Test `wasmtime-wasi-tls-nativetls` & `wasmtime-wasi-tls-openssl` in their
# own job. This is because they depends on OpenSSL, which is not easily
# available on all platforms.
#
# The Windows base image has OpenSSL installed by default, but not in a way
# that is automatically discoverable by `openssl-sys`. We need to configure
# the OPENSSL_DIR & OPENSSL_LIB_DIR paths manually.
# Additionally, the GH actions Windows image does not ship with a CA cert
# bundle, so we use the one from cUrl.
test_wasi_tls:
name: Test wasi-tls using native-tls & openssl providers
needs: determine
if: needs.determine.outputs.run-full
runs-on: ${{ matrix.os }}
Expand All @@ -947,6 +954,19 @@ jobs:
with:
submodules: true
- uses: ./.github/actions/install-rust
- name: Configure OpenSSL (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
mkdir "C:\Program Files\OpenSSL\certs"
$sslCertFile = "C:\Program Files\OpenSSL\certs\cacert.pem"
$opensslDir = "C:\Program Files\OpenSSL"
$opensslLibDir = "C:\Program Files\OpenSSL\lib\VC\x64\MD"
curl.exe -o $sslCertFile https://curl.se/ca/cacert.pem
"SSL_CERT_FILE=$sslCertFile" | Out-File -FilePath $env:GITHUB_ENV -Append
"OPENSSL_DIR=$opensslDir" | Out-File -FilePath $env:GITHUB_ENV -Append
"OPENSSL_LIB_DIR=$opensslLibDir" | Out-File -FilePath $env:GITHUB_ENV -Append
- run: cargo test -p wasmtime-wasi-tls-openssl
- run: cargo test -p wasmtime-wasi-tls-nativetls

# Test the `wasmtime-fuzzing` crate. Split out from the main tests because
Expand Down Expand Up @@ -1259,7 +1279,7 @@ jobs:
- doc
- micro_checks
- special_tests
- test_wasi_tls_nativetls
- test_wasi_tls
- clippy
- monolith_checks
- platform_checks
Expand Down
26 changes: 26 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ members = [
"crates/wasi-preview1-component-adapter",
"crates/wasi-preview1-component-adapter/verify",
"crates/wasi-tls-nativetls",
"crates/wasi-tls-openssl",
"crates/debugger",
"crates/wizer/fuzz",
"crates/wizer/tests/regex-test",
Expand Down Expand Up @@ -251,6 +252,7 @@ wasmtime-wasi-keyvalue = { path = "crates/wasi-keyvalue", version = "42.0.0" }
wasmtime-wasi-threads = { path = "crates/wasi-threads", version = "42.0.0" }
wasmtime-wasi-tls = { path = "crates/wasi-tls", version = "42.0.0" }
wasmtime-wasi-tls-nativetls = { path = "crates/wasi-tls-nativetls", version = "42.0.0" }
wasmtime-wasi-tls-openssl = { path = "crates/wasi-tls-openssl", version = "42.0.0" }
wasmtime-wast = { path = "crates/wast", version = "=42.0.0" }

# Internal Wasmtime-specific crates.
Expand Down Expand Up @@ -423,6 +425,9 @@ tokio-rustls = "0.25.0"
rustls = "0.22.0"
tokio-native-tls = "0.3.1"
native-tls = "0.2.11"
tokio-openssl = "0.6.5"
openssl = "0.10.73"
openssl-sys = "0.9.109"
webpki-roots = "0.26.0"
itertools = "0.14.0"
base64 = "0.22.1"
Expand Down
4 changes: 4 additions & 0 deletions ci/run-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
# - wasmtime-wasi-tls-nativetls: the openssl dependency does not play nice with
# cross compilation. This crate is tested in a separate CI job.
#
# - wasmtime-wasi-tls-openssl: the openssl dependency does not play nice with
# cross compilation. This crate is tested in a separate CI job.
#
# - wasmtime-fuzzing: enabling all features brings in OCaml which is a pain to
# configure for all targets, so it has its own CI job.
#
Expand All @@ -27,6 +30,7 @@
args.append('--exclude=test-programs')
args.append('--exclude=wasmtime-wasi-nn')
args.append('--exclude=wasmtime-wasi-tls-nativetls')
args.append('--exclude=wasmtime-wasi-tls-openssl')
args.append('--exclude=wasmtime-fuzzing')
args.append('--exclude=wasm-spec-interpreter')
args.append('--exclude=veri_engine')
Expand Down
26 changes: 26 additions & 0 deletions crates/wasi-tls-openssl/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "wasmtime-wasi-tls-openssl"
version.workspace = true
authors.workspace = true
edition.workspace = true
rust-version.workspace = true
repository = "https://github.com/bytecodealliance/wasmtime"
license = "Apache-2.0 WITH LLVM-exception"
description = "Wasmtime implementation of the wasi-tls API, using OpenSSL for TLS support."

[lints]
workspace = true

[dependencies]
wasmtime-wasi-tls = { workspace = true }
tokio = { workspace = true }
tokio-openssl = { workspace = true }
openssl = { workspace = true }

[dev-dependencies]
anyhow = { workspace = true }
test-programs-artifacts = { workspace = true }
wasmtime = { workspace = true, features = ["runtime", "component-model"] }
wasmtime-wasi = { workspace = true }
tokio = { workspace = true, features = ["macros"] }
futures = { workspace = true }
94 changes: 94 additions & 0 deletions crates/wasi-tls-openssl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//! The `openssl` provider.

use openssl::ssl::{SslConnector, SslMethod};
use std::{
io,
pin::{Pin, pin},
};
use wasmtime_wasi_tls::{TlsProvider, TlsStream, TlsTransport};

type BoxFuture<T> = std::pin::Pin<Box<dyn Future<Output = T> + Send>>;

/// The `openssl` provider.
pub struct OpenSslProvider {
_priv: (),
}

impl TlsProvider for OpenSslProvider {
fn connect(
&self,
server_name: String,
transport: Box<dyn TlsTransport>,
) -> BoxFuture<io::Result<Box<dyn TlsStream>>> {
async fn connect_impl(
server_name: String,
transport: Box<dyn TlsTransport>,
) -> Result<OpenSslStream, openssl::ssl::Error> {
// Per the `openssl` crate's recommendation, we're using the
// `SslConnector` to set up a Ssl object with secure defaults:
//
// https://docs.rs/openssl/latest/openssl/ssl/struct.SslConnector.html
// > OpenSSL's default configuration is highly insecure. This
// > connector manages the OpenSSL structures, configuring cipher
// > suites, session options, hostname verification, and more.
let config = SslConnector::builder(SslMethod::tls_client())?
.build()
.configure()?;
let ssl = config.into_ssl(&server_name)?;
let mut stream = tokio_openssl::SslStream::new(ssl, transport)?;
Pin::new(&mut stream).connect().await?;
Ok(OpenSslStream(stream))
}

Box::pin(async move {
let stream = connect_impl(server_name, transport)
.await
.map_err(|e| io::Error::other(e))?;
Ok(Box::new(stream) as Box<dyn TlsStream>)
})
}
}

impl Default for OpenSslProvider {
fn default() -> Self {
Self { _priv: () }
}
}

struct OpenSslStream(tokio_openssl::SslStream<Box<dyn TlsTransport>>);

impl TlsStream for OpenSslStream {}

impl tokio::io::AsyncRead for OpenSslStream {
fn poll_read(
mut self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &mut tokio::io::ReadBuf<'_>,
) -> std::task::Poll<io::Result<()>> {
pin!(&mut self.as_mut().0).poll_read(cx, buf)
}
}

impl tokio::io::AsyncWrite for OpenSslStream {
fn poll_write(
mut self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &[u8],
) -> std::task::Poll<io::Result<usize>> {
pin!(&mut self.as_mut().0).poll_write(cx, buf)
}

fn poll_flush(
mut self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), io::Error>> {
pin!(&mut self.as_mut().0).poll_flush(cx)
}

fn poll_shutdown(
mut self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), io::Error>> {
pin!(&mut self.as_mut().0).poll_shutdown(cx)
}
}
70 changes: 70 additions & 0 deletions crates/wasi-tls-openssl/tests/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use anyhow::{Result, anyhow};
use wasmtime::{
Store,
component::{Component, Linker, ResourceTable},
};
use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView, p2::bindings::Command};
use wasmtime_wasi_tls::{LinkOptions, WasiTls, WasiTlsCtx, WasiTlsCtxBuilder};

struct Ctx {
table: ResourceTable,
wasi_ctx: WasiCtx,
wasi_tls_ctx: WasiTlsCtx,
}

impl WasiView for Ctx {
fn ctx(&mut self) -> WasiCtxView<'_> {
WasiCtxView {
ctx: &mut self.wasi_ctx,
table: &mut self.table,
}
}
}

async fn run_test(path: &str) -> Result<()> {
let provider = Box::new(wasmtime_wasi_tls_openssl::OpenSslProvider::default());
let ctx = Ctx {
table: ResourceTable::new(),
wasi_ctx: WasiCtx::builder()
.inherit_stderr()
.inherit_network()
.allow_ip_name_lookup(true)
.build(),
wasi_tls_ctx: WasiTlsCtxBuilder::new().provider(provider).build(),
};

let engine = test_programs_artifacts::engine(|config| {
config.async_support(true);
});
let mut store = Store::new(&engine, ctx);
let component = Component::from_file(&engine, path)?;

let mut linker = Linker::new(&engine);
wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;
let mut opts = LinkOptions::default();
opts.tls(true);
wasmtime_wasi_tls::add_to_linker(&mut linker, &mut opts, |h: &mut Ctx| {
WasiTls::new(&h.wasi_tls_ctx, &mut h.table)
})?;

let command = Command::instantiate_async(&mut store, &component, &linker).await?;
command
.wasi_cli_run()
.call_run(&mut store)
.await?
.map_err(|()| anyhow!("command returned with failing exit status"))
}

macro_rules! assert_test_exists {
($name:ident) => {
#[expect(unused_imports, reason = "just here to assert it exists")]
use self::$name as _;
};
}

test_programs_artifacts::foreach_tls!(assert_test_exists);

#[tokio::test(flavor = "multi_thread")]
async fn tls_sample_application() -> Result<()> {
run_test(test_programs_artifacts::TLS_SAMPLE_APPLICATION_COMPONENT).await
}
2 changes: 2 additions & 0 deletions scripts/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const CRATES_TO_PUBLISH: &[&str] = &[
"wasmtime-wasi-threads",
"wasmtime-wasi-tls",
"wasmtime-wasi-tls-nativetls",
"wasmtime-wasi-tls-openssl",
"wasmtime-wast",
"wasmtime-internal-c-api-macros",
"wasmtime-c-api-impl",
Expand All @@ -100,6 +101,7 @@ const PUBLIC_CRATES: &[&str] = &[
"wasmtime-wasi",
"wasmtime-wasi-tls",
"wasmtime-wasi-tls-nativetls",
"wasmtime-wasi-tls-openssl",
"wasmtime-wasi-http",
"wasmtime-wasi-nn",
"wasmtime-wasi-config",
Expand Down
20 changes: 20 additions & 0 deletions supply-chain/audits.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1450,6 +1450,14 @@ start = "2026-01-07"
end = "2027-01-08"
notes = "The Bytecode Alliance is the author of this crate"

[[wildcard-audits.wasmtime-wasi-tls-openssl]]
who = "Alex Crichton <alex@alexcrichton.com>"
criteria = "safe-to-deploy"
trusted-publisher = "github:bytecodealliance/wasmtime"
start = "2026-01-07"
end = "2027-01-08"
notes = "The Bytecode Alliance is the author of this crate"

[[wildcard-audits.wasmtime-wast]]
who = "Alex Crichton <alex@alexcrichton.com>"
criteria = "safe-to-deploy"
Expand Down Expand Up @@ -4689,6 +4697,12 @@ criteria = "safe-to-deploy"
version = "0.3.1"
notes = "unsafety is used for smuggling std::task::Context as a raw pointer. Lifetime and type safety appears to be taken care of correctly."

[[audits.tokio-openssl]]
who = "Alex Crichton <alex@alexcrichton.com>"
criteria = "safe-to-deploy"
version = "0.6.5"
notes = "Minor usage of `unsafe` but not obviously incorrect or problematic. Does not use any undue ambient state or anything like that, does what it says on the tin."

[[audits.tokio-rustls]]
who = "Pat Hickey <phickey@fastly.com>"
criteria = "safe-to-deploy"
Expand Down Expand Up @@ -5728,6 +5742,12 @@ criteria = "safe-to-deploy"
delta = "0.243.0 -> 0.244.0"
notes = "The Bytecode Alliance is the author of this crate"

[[audits.wasmtime-wasi-tls-openssl]]
who = "Dave Bakker <github@davebakker.io>"
criteria = "safe-to-deploy"
version = "0.0.1"
notes = "The Bytecode Alliance is the author of this crate."

[[audits.wast]]
who = "Alex Crichton <alex@alexcrichton.com>"
criteria = "safe-to-deploy"
Expand Down
3 changes: 3 additions & 0 deletions supply-chain/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ audit-as-crates-io = true
[policy.wasmtime-wasi-tls-nativetls]
audit-as-crates-io = true

[policy.wasmtime-wasi-tls-openssl]
audit-as-crates-io = true

[policy.wasmtime-wast]
audit-as-crates-io = true

Expand Down
Loading