Skip to content

Commit b85addc

Browse files
Add native-tls backend for wasi-tls (#11064)
* Reorganize the wasi-tls folder and isolate the `rustls`-specific bits from the rest of the implementation. - `client.rs`: The rustls parts. - `io.rs`: WASI I/O conversion utility types. - `host.rs`: The host types + impls. - `bindings.rs`: The generated bindings. * Add `native-tls` backend * Improve compatibility of `test_tls_sample_application`: It used to perform a "half-close" after sending the HTTP request. This is a TLS1.3+ feature, though Rustls & OpenSSL already supported it for TLS1.2 and lower. Technically, that makes them non-spec compliant, but they chose to align with the semantics of the underlying TCP connection. I suspect the TLS1.3 spec was updated to match what was already happening in reality. Anyhow, SChannel does not support half-closed connections and so the `read` call after the `close_output+shutdown` failed. I've reordered the test to first perform the HTTP conversation and _then_ do the TLS+TCP teardown. * Implement flushing on the `AsyncWriteStream`. The `AsyncWriteStream` implementation was copied from the TCP equivalent, which doesn't need flushing. The TLS implementations _do_ maintain an internal buffer, so the `flush` call need to be hooked up. * Switch to a model that uses runtime configuration. * Check wasmtime-wasi-tls features in isolation. * Clarify intended use of `WasiTlsCtxBuilder::provider` * Split off native-tls implementation into separate crate * Add a dedicated Ci job to test the `native-tls` backend. prtest:full * Update vets --------- Co-authored-by: Alex Crichton <[email protected]>
1 parent 1e82443 commit b85addc

File tree

18 files changed

+1109
-628
lines changed

18 files changed

+1109
-628
lines changed

.github/workflows/main.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,23 @@ jobs:
812812
# Run the tests!
813813
- run: cargo test -p wasmtime-wasi-nn --features ${{ matrix.feature }}
814814

815+
# Test `wasmtime-wasi-tls-nativetls` in its own job. This is because it
816+
# depends on OpenSSL, which is not easily available on all platforms.
817+
test_wasi_tls_nativetls:
818+
name: Test wasi-tls using native-tls provider
819+
needs: determine
820+
if: needs.determine.outputs.run-full
821+
runs-on: ${{ matrix.os }}
822+
strategy:
823+
matrix:
824+
os: [ubuntu-latest, windows-latest, macos-latest]
825+
steps:
826+
- uses: actions/checkout@v4
827+
with:
828+
submodules: true
829+
- uses: ./.github/actions/install-rust
830+
- run: cargo test -p wasmtime-wasi-tls-nativetls
831+
815832
# Test the `wasmtime-fuzzing` crate. Split out from the main tests because
816833
# `--all-features` brings in OCaml, which is a pain to get setup for all
817834
# targets.
@@ -1114,6 +1131,7 @@ jobs:
11141131
- doc
11151132
- micro_checks
11161133
- special_tests
1134+
- test_wasi_tls_nativetls
11171135
- clippy
11181136
- monolith_checks
11191137
- platform_checks

Cargo.lock

Lines changed: 149 additions & 0 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
@@ -158,6 +158,7 @@ members = [
158158
"crates/test-programs",
159159
"crates/wasi-preview1-component-adapter",
160160
"crates/wasi-preview1-component-adapter/verify",
161+
"crates/wasi-tls-nativetls",
161162
"examples/fib-debug/wasm",
162163
"examples/wasm",
163164
"examples/tokio/wasm",
@@ -235,6 +236,7 @@ wasmtime-wasi-config = { path = "crates/wasi-config", version = "35.0.0" }
235236
wasmtime-wasi-keyvalue = { path = "crates/wasi-keyvalue", version = "35.0.0" }
236237
wasmtime-wasi-threads = { path = "crates/wasi-threads", version = "35.0.0" }
237238
wasmtime-wasi-tls = { path = "crates/wasi-tls", version = "35.0.0" }
239+
wasmtime-wasi-tls-nativetls = { path = "crates/wasi-tls-nativetls", version = "35.0.0" }
238240
wasmtime-wast = { path = "crates/wast", version = "=35.0.0" }
239241

240242
# Internal Wasmtime-specific crates.
@@ -399,6 +401,8 @@ ittapi = "0.4.0"
399401
libm = "0.2.7"
400402
tokio-rustls = "0.25.0"
401403
rustls = "0.22.0"
404+
tokio-native-tls = "0.3.1"
405+
native-tls = "0.2.11"
402406
webpki-roots = "0.26.0"
403407
itertools = "0.14.0"
404408
base64 = "0.22.1"

ci/run-tests.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
# - wasmtime-wasi-nn: mutually-exclusive features that aren't available for all
88
# targets, needs its own CI job.
99
#
10+
# - wasmtime-wasi-tls-nativetls: the openssl dependency does not play nice with
11+
# cross compilation. This crate is tested in a separate CI job.
12+
#
1013
# - wasmtime-fuzzing: enabling all features brings in OCaml which is a pain to
1114
# configure for all targets, so it has its own CI job.
1215
#
@@ -21,6 +24,7 @@
2124
args = ['cargo', 'test', '--workspace', '--all-features']
2225
args.append('--exclude=test-programs')
2326
args.append('--exclude=wasmtime-wasi-nn')
27+
args.append('--exclude=wasmtime-wasi-tls-nativetls')
2428
args.append('--exclude=wasmtime-fuzzing')
2529
args.append('--exclude=wasm-spec-interpreter')
2630
args.append('--exclude=veri_engine')

crates/test-programs/src/bin/tls_sample_application.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ use test_programs::wasi::tls::types::ClientHandshake;
77
const PORT: u16 = 443;
88

99
fn test_tls_sample_application(domain: &str, ip: IpAddress) -> Result<()> {
10-
let request =
11-
format!("GET / HTTP/1.1\r\nHost: {domain}\r\nUser-Agent: wasmtime-wasi-rust\r\n\r\n");
10+
let request = format!(
11+
"GET / HTTP/1.1\r\nHost: {domain}\r\nUser-Agent: wasmtime-wasi-rust\r\nConnection: close\r\n\r\n"
12+
);
1213

1314
let net = Network::default();
1415

@@ -25,13 +26,13 @@ fn test_tls_sample_application(domain: &str, ip: IpAddress) -> Result<()> {
2526
tls_output
2627
.blocking_write_util(request.as_bytes())
2728
.context("writing http request failed")?;
28-
client_connection
29-
.blocking_close_output(&tls_output)
30-
.context("closing tls connection failed")?;
31-
socket.shutdown(ShutdownType::Send)?;
3229
let response = tls_input
3330
.blocking_read_to_end()
3431
.context("reading http response failed")?;
32+
client_connection
33+
.blocking_close_output(&tls_output)
34+
.context("closing tls connection failed")?;
35+
socket.shutdown(ShutdownType::Both)?;
3536

3637
if String::from_utf8(response)?.contains("HTTP/1.1 200 OK") {
3738
Ok(())
@@ -55,7 +56,7 @@ fn test_tls_invalid_certificate(_domain: &str, ip: IpAddress) -> Result<()> {
5556

5657
match ClientHandshake::new(BAD_DOMAIN, tcp_input, tcp_output).blocking_finish() {
5758
// We're expecting an error regarding the "certificate" is some form or
58-
// another. When we add more TLS backends other than rustls, this naive
59+
// another. When we add more TLS backends this naive
5960
// check will likely need to be revisited/expanded:
6061
Err(e) if e.to_debug_string().contains("certificate") => Ok(()),
6162

crates/wasi-tls-nativetls/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-nativetls"
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 native-tls for TLS support."
10+
11+
[lints]
12+
workspace = true
13+
14+
[dependencies]
15+
wasmtime-wasi-tls = { workspace = true }
16+
tokio = { workspace = true }
17+
tokio-native-tls = { workspace = true }
18+
native-tls = { 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 }

0 commit comments

Comments
 (0)