Skip to content

Commit 1def31c

Browse files
committed
Create an OpenSSL backend for wasi-tls
prtest:full
1 parent bbd12e9 commit 1def31c

File tree

8 files changed

+237
-9
lines changed

8 files changed

+237
-9
lines changed

.github/workflows/main.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -931,10 +931,11 @@ jobs:
931931
# Run the tests!
932932
- run: cargo test -p wasmtime-wasi-nn --features ${{ matrix.feature }}
933933

934-
# Test `wasmtime-wasi-tls-nativetls` in its own job. This is because it
935-
# depends on OpenSSL, which is not easily available on all platforms.
936-
test_wasi_tls_nativetls:
937-
name: Test wasi-tls using native-tls provider
934+
# Test `wasmtime-wasi-tls-nativetls` & `wasmtime-wasi-tls-openssl` in its own
935+
# job. This is because they depend on OpenSSL, which is not easily available
936+
# on all platforms.
937+
test_wasi_tls:
938+
name: Test wasi-tls using native-tls & openssl providers
938939
needs: determine
939940
if: needs.determine.outputs.run-full
940941
runs-on: ${{ matrix.os }}
@@ -946,6 +947,7 @@ jobs:
946947
with:
947948
submodules: true
948949
- uses: ./.github/actions/install-rust
950+
- run: cargo test -p wasmtime-wasi-tls-openssl
949951
- run: cargo test -p wasmtime-wasi-tls-nativetls
950952

951953
# Test the `wasmtime-fuzzing` crate. Split out from the main tests because
@@ -1258,7 +1260,7 @@ jobs:
12581260
- doc
12591261
- micro_checks
12601262
- special_tests
1261-
- test_wasi_tls_nativetls
1263+
- test_wasi_tls
12621264
- clippy
12631265
- monolith_checks
12641266
- platform_checks

Cargo.lock

Lines changed: 30 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ members = [
164164
"crates/wasi-preview1-component-adapter",
165165
"crates/wasi-preview1-component-adapter/verify",
166166
"crates/wasi-tls-nativetls",
167+
"crates/wasi-tls-openssl",
167168
"crates/debugger",
168169
"crates/wizer/fuzz",
169170
"crates/wizer/tests/regex-test",
@@ -251,6 +252,7 @@ wasmtime-wasi-keyvalue = { path = "crates/wasi-keyvalue", version = "41.0.0" }
251252
wasmtime-wasi-threads = { path = "crates/wasi-threads", version = "41.0.0" }
252253
wasmtime-wasi-tls = { path = "crates/wasi-tls", version = "41.0.0" }
253254
wasmtime-wasi-tls-nativetls = { path = "crates/wasi-tls-nativetls", version = "41.0.0" }
255+
wasmtime-wasi-tls-openssl = { path = "crates/wasi-tls-openssl", version = "41.0.0" }
254256
wasmtime-wast = { path = "crates/wast", version = "=41.0.0" }
255257

256258
# Internal Wasmtime-specific crates.
@@ -423,6 +425,8 @@ tokio-rustls = "0.25.0"
423425
rustls = "0.22.0"
424426
tokio-native-tls = "0.3.1"
425427
native-tls = "0.2.11"
428+
tokio-openssl = "0.6.5"
429+
openssl = "0.10.75"
426430
webpki-roots = "0.26.0"
427431
itertools = "0.14.0"
428432
base64 = "0.22.1"

ci/run-tests.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
# - wasmtime-wasi-tls-nativetls: the openssl dependency does not play nice with
1111
# cross compilation. This crate is tested in a separate CI job.
1212
#
13+
# - wasmtime-wasi-tls-openssl: the openssl dependency does not play nice with
14+
# cross compilation. This crate is tested in a separate CI job.
15+
#
1316
# - wasmtime-fuzzing: enabling all features brings in OCaml which is a pain to
1417
# configure for all targets, so it has its own CI job.
1518
#
@@ -27,6 +30,7 @@
2730
args.append('--exclude=test-programs')
2831
args.append('--exclude=wasmtime-wasi-nn')
2932
args.append('--exclude=wasmtime-wasi-tls-nativetls')
33+
args.append('--exclude=wasmtime-wasi-tls-openssl')
3034
args.append('--exclude=wasmtime-fuzzing')
3135
args.append('--exclude=wasm-spec-interpreter')
3236
args.append('--exclude=veri_engine')

crates/wasi-tls-openssl/Cargo.toml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[package]
2+
name = "wasmtime-wasi-tls-openssl"
3+
version.workspace = true
4+
authors.workspace = true
5+
edition.workspace = true
6+
rust-version.workspace = true
7+
repository = "https://github.com/bytecodealliance/wasmtime"
8+
license = "Apache-2.0 WITH LLVM-exception"
9+
description = "Wasmtime implementation of the wasi-tls API, using OpenSSL for TLS support."
10+
11+
[lints]
12+
workspace = true
13+
14+
[dependencies]
15+
wasmtime-wasi-tls = { workspace = true }
16+
tokio = { workspace = true }
17+
tokio-openssl = { workspace = true }
18+
openssl = { workspace = true }
19+
20+
[dev-dependencies]
21+
anyhow = { workspace = true }
22+
test-programs-artifacts = { workspace = true }
23+
wasmtime = { workspace = true, features = ["runtime", "component-model"] }
24+
wasmtime-wasi = { workspace = true }
25+
tokio = { workspace = true, features = ["macros"] }
26+
futures = { workspace = true }

crates/wasi-tls-openssl/src/lib.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//! The `openssl` provider.
2+
3+
use openssl::ssl::{SslConnector, SslMethod};
4+
use std::{
5+
io,
6+
pin::{Pin, pin},
7+
};
8+
use wasmtime_wasi_tls::{TlsProvider, TlsStream, TlsTransport};
9+
10+
type BoxFuture<T> = std::pin::Pin<Box<dyn Future<Output = T> + Send>>;
11+
12+
/// The `openssl` provider.
13+
pub struct OpenSslProvider {
14+
_priv: (),
15+
}
16+
17+
impl TlsProvider for OpenSslProvider {
18+
fn connect(
19+
&self,
20+
server_name: String,
21+
transport: Box<dyn TlsTransport>,
22+
) -> BoxFuture<io::Result<Box<dyn TlsStream>>> {
23+
async fn connect_impl(
24+
server_name: String,
25+
transport: Box<dyn TlsTransport>,
26+
) -> Result<OpenSslStream, openssl::ssl::Error> {
27+
// Per the `openssl` crate's recommendation, we're using the
28+
// `SslConnector` to set up a Ssl object with secure defaults:
29+
//
30+
// https://docs.rs/openssl/latest/openssl/ssl/struct.SslConnector.html
31+
// > OpenSSL's default configuration is highly insecure. This
32+
// > connector manages the OpenSSL structures, configuring cipher
33+
// > suites, session options, hostname verification, and more.
34+
let config = SslConnector::builder(SslMethod::tls_client())?
35+
.build()
36+
.configure()?;
37+
let ssl = config.into_ssl(&server_name)?;
38+
let mut stream = tokio_openssl::SslStream::new(ssl, transport)?;
39+
Pin::new(&mut stream).connect().await?;
40+
Ok(OpenSslStream(stream))
41+
}
42+
43+
Box::pin(async move {
44+
let stream = connect_impl(server_name, transport)
45+
.await
46+
.map_err(|e| io::Error::other(e))?;
47+
Ok(Box::new(stream) as Box<dyn TlsStream>)
48+
})
49+
}
50+
}
51+
52+
impl Default for OpenSslProvider {
53+
fn default() -> Self {
54+
Self { _priv: () }
55+
}
56+
}
57+
58+
struct OpenSslStream(tokio_openssl::SslStream<Box<dyn TlsTransport>>);
59+
60+
impl TlsStream for OpenSslStream {}
61+
62+
impl tokio::io::AsyncRead for OpenSslStream {
63+
fn poll_read(
64+
mut self: std::pin::Pin<&mut Self>,
65+
cx: &mut std::task::Context<'_>,
66+
buf: &mut tokio::io::ReadBuf<'_>,
67+
) -> std::task::Poll<io::Result<()>> {
68+
pin!(&mut self.as_mut().0).poll_read(cx, buf)
69+
}
70+
}
71+
72+
impl tokio::io::AsyncWrite for OpenSslStream {
73+
fn poll_write(
74+
mut self: std::pin::Pin<&mut Self>,
75+
cx: &mut std::task::Context<'_>,
76+
buf: &[u8],
77+
) -> std::task::Poll<io::Result<usize>> {
78+
pin!(&mut self.as_mut().0).poll_write(cx, buf)
79+
}
80+
81+
fn poll_flush(
82+
mut self: std::pin::Pin<&mut Self>,
83+
cx: &mut std::task::Context<'_>,
84+
) -> std::task::Poll<Result<(), io::Error>> {
85+
pin!(&mut self.as_mut().0).poll_flush(cx)
86+
}
87+
88+
fn poll_shutdown(
89+
mut self: std::pin::Pin<&mut Self>,
90+
cx: &mut std::task::Context<'_>,
91+
) -> std::task::Poll<Result<(), io::Error>> {
92+
pin!(&mut self.as_mut().0).poll_shutdown(cx)
93+
}
94+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use anyhow::{Result, anyhow};
2+
use wasmtime::{
3+
Store,
4+
component::{Component, Linker, ResourceTable},
5+
};
6+
use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView, p2::bindings::Command};
7+
use wasmtime_wasi_tls::{LinkOptions, WasiTls, WasiTlsCtx, WasiTlsCtxBuilder};
8+
9+
struct Ctx {
10+
table: ResourceTable,
11+
wasi_ctx: WasiCtx,
12+
wasi_tls_ctx: WasiTlsCtx,
13+
}
14+
15+
impl WasiView for Ctx {
16+
fn ctx(&mut self) -> WasiCtxView<'_> {
17+
WasiCtxView {
18+
ctx: &mut self.wasi_ctx,
19+
table: &mut self.table,
20+
}
21+
}
22+
}
23+
24+
async fn run_test(path: &str) -> Result<()> {
25+
let provider = Box::new(wasmtime_wasi_tls_openssl::OpenSslProvider::default());
26+
let ctx = Ctx {
27+
table: ResourceTable::new(),
28+
wasi_ctx: WasiCtx::builder()
29+
.inherit_stderr()
30+
.inherit_network()
31+
.allow_ip_name_lookup(true)
32+
.build(),
33+
wasi_tls_ctx: WasiTlsCtxBuilder::new().provider(provider).build(),
34+
};
35+
36+
let engine = test_programs_artifacts::engine(|config| {
37+
config.async_support(true);
38+
});
39+
let mut store = Store::new(&engine, ctx);
40+
let component = Component::from_file(&engine, path)?;
41+
42+
let mut linker = Linker::new(&engine);
43+
wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;
44+
let mut opts = LinkOptions::default();
45+
opts.tls(true);
46+
wasmtime_wasi_tls::add_to_linker(&mut linker, &mut opts, |h: &mut Ctx| {
47+
WasiTls::new(&h.wasi_tls_ctx, &mut h.table)
48+
})?;
49+
50+
let command = Command::instantiate_async(&mut store, &component, &linker).await?;
51+
command
52+
.wasi_cli_run()
53+
.call_run(&mut store)
54+
.await?
55+
.map_err(|()| anyhow!("command returned with failing exit status"))
56+
}
57+
58+
macro_rules! assert_test_exists {
59+
($name:ident) => {
60+
#[expect(unused_imports, reason = "just here to assert it exists")]
61+
use self::$name as _;
62+
};
63+
}
64+
65+
test_programs_artifacts::foreach_tls!(assert_test_exists);
66+
67+
#[tokio::test(flavor = "multi_thread")]
68+
async fn tls_sample_application() -> Result<()> {
69+
run_test(test_programs_artifacts::TLS_SAMPLE_APPLICATION_COMPONENT).await
70+
}

scripts/publish.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ const CRATES_TO_PUBLISH: &[&str] = &[
8181
"wasmtime-wasi-threads",
8282
"wasmtime-wasi-tls",
8383
"wasmtime-wasi-tls-nativetls",
84+
"wasmtime-wasi-tls-openssl",
8485
"wasmtime-wast",
8586
"wasmtime-internal-c-api-macros",
8687
"wasmtime-c-api-impl",
@@ -103,6 +104,7 @@ const PUBLIC_CRATES: &[&str] = &[
103104
"wasmtime-wasi",
104105
"wasmtime-wasi-tls",
105106
"wasmtime-wasi-tls-nativetls",
107+
"wasmtime-wasi-tls-openssl",
106108
"wasmtime-wasi-http",
107109
"wasmtime-wasi-nn",
108110
"wasmtime-wasi-config",

0 commit comments

Comments
 (0)