Skip to content

Commit f870a70

Browse files
committed
feat: support custom root certificates in WASM bindings (#618)
Add `root_certs` option to `ProverConfig` and `VerifierConfig` in sdk-core and WASM bindings, allowing custom DER-encoded root certificates for TLS server verification. When not provided, Mozilla root certificates are used as the default. - Add `root_certs: Option<Vec<Vec<u8>>>` to sdk-core configs with builder methods - Add `mozilla-certs` feature flag to sdk-core for conditional fallback - Wire custom root certs through WASM prover/verifier config layers - Remove stale `tests.rs` and unused `test` feature from wasm crate - Clean up unused wasm dependencies (tlsn, tlsn-core, tlsn-tls-core, tlsn-server-fixture-certs) - Add `sdk_core` harness test plugin exercising the full MPC-TLS flow with custom root certs Closes #618
1 parent 77a8a25 commit f870a70

File tree

14 files changed

+167
-133
lines changed

14 files changed

+167
-133
lines changed

Cargo.lock

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

crates/harness/executor/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ crate-type = ["cdylib", "rlib"]
1717
[dependencies]
1818
tlsn-harness-core = { workspace = true }
1919
tlsn = { workspace = true }
20+
tlsn-sdk-core = { workspace = true }
2021
tlsn-server-fixture-certs = { workspace = true }
2122

2223
inventory = { workspace = true }
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use tlsn_sdk_core::{
2+
HttpRequest, NetworkSetting, ProverConfig, Reveal, SdkProver, SdkVerifier, VerifierConfig,
3+
};
4+
use tlsn_server_fixture_certs::{CA_CERT_DER, SERVER_DOMAIN};
5+
6+
use crate::IoProvider;
7+
8+
// Maximum number of bytes that can be sent from prover to server
9+
const MAX_SENT_DATA: usize = 1 << 11;
10+
// Maximum number of bytes that can be received by prover from server
11+
const MAX_RECV_DATA: usize = 1 << 11;
12+
13+
crate::test!("sdk_core", prover, verifier);
14+
15+
async fn prover(provider: &IoProvider) {
16+
let config = ProverConfig::builder(SERVER_DOMAIN)
17+
.max_sent_data(MAX_SENT_DATA)
18+
.max_recv_data(MAX_RECV_DATA)
19+
.defer_decryption_from_start(true)
20+
.network(NetworkSetting::Latency)
21+
.root_certs(vec![CA_CERT_DER.to_vec()])
22+
.build();
23+
24+
let mut prover = SdkProver::new(config).unwrap();
25+
26+
let proto_io = provider.provide_proto_io().await.unwrap();
27+
prover.setup(proto_io).await.unwrap();
28+
29+
let server_io = provider.provide_server_io().await.unwrap();
30+
let request = HttpRequest::get(&format!(
31+
"https://{}/bytes?size={}",
32+
SERVER_DOMAIN,
33+
MAX_RECV_DATA - 256
34+
))
35+
.header("Host", SERVER_DOMAIN)
36+
.header("Connection", "close");
37+
38+
let response = prover.send_request(server_io, request).await.unwrap();
39+
assert_eq!(response.status, 200);
40+
41+
let transcript = prover.transcript().unwrap();
42+
let sent_len = transcript.sent.len();
43+
let recv_len = transcript.recv.len();
44+
45+
prover
46+
.reveal(
47+
Reveal::new()
48+
.sent(0..sent_len - 1)
49+
.recv(2..recv_len)
50+
.server_identity(true),
51+
)
52+
.await
53+
.unwrap();
54+
55+
assert!(prover.is_complete());
56+
}
57+
58+
async fn verifier(provider: &IoProvider) {
59+
let config = VerifierConfig::builder()
60+
.max_sent_data(MAX_SENT_DATA)
61+
.max_recv_data(MAX_RECV_DATA)
62+
.root_certs(vec![CA_CERT_DER.to_vec()])
63+
.build();
64+
65+
let mut verifier = SdkVerifier::new(config);
66+
67+
let proto_io = provider.provide_proto_io().await.unwrap();
68+
verifier.connect(proto_io).await.unwrap();
69+
70+
let output = verifier.verify().await.unwrap();
71+
72+
assert_eq!(output.server_name.as_deref(), Some(SERVER_DOMAIN));
73+
assert!(output.transcript.is_some());
74+
assert!(verifier.is_complete());
75+
}

crates/sdk-core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ workspace = true
1313

1414
[features]
1515
default = []
16+
mozilla-certs = ["tlsn/mozilla-certs"]
1617
wasm = ["wasm-bindgen-futures"]
1718

1819
[dependencies]

crates/sdk-core/src/config.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
//! Configuration types for the SDK.
22
33
use serde::{Deserialize, Serialize};
4+
use tlsn::webpki::{CertificateDer, RootCertStore};
5+
6+
use crate::error::Result;
7+
#[cfg(not(feature = "mozilla-certs"))]
8+
use crate::error::SdkError;
49

510
/// Configuration for the Prover.
611
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -23,6 +28,10 @@ pub struct ProverConfig {
2328
pub network: NetworkSetting,
2429
/// Optional client authentication credentials (certificates, private key).
2530
pub client_auth: Option<ClientAuth>,
31+
/// Custom root certificates (DER-encoded) for TLS server verification.
32+
///
33+
/// If `None`, the Mozilla root certificates are used.
34+
pub root_certs: Option<Vec<Vec<u8>>>,
2635
}
2736

2837
impl ProverConfig {
@@ -44,6 +53,7 @@ pub struct ProverConfigBuilder {
4453
defer_decryption_from_start: Option<bool>,
4554
network: NetworkSetting,
4655
client_auth: Option<ClientAuth>,
56+
root_certs: Option<Vec<Vec<u8>>>,
4757
}
4858

4959
impl ProverConfigBuilder {
@@ -59,6 +69,7 @@ impl ProverConfigBuilder {
5969
defer_decryption_from_start: None,
6070
network: NetworkSetting::Latency,
6171
client_auth: None,
72+
root_certs: None,
6273
}
6374
}
6475

@@ -110,6 +121,14 @@ impl ProverConfigBuilder {
110121
self
111122
}
112123

124+
/// Sets custom root certificates (DER-encoded) for TLS server verification.
125+
///
126+
/// If not set, the Mozilla root certificates are used.
127+
pub fn root_certs(mut self, certs: Vec<Vec<u8>>) -> Self {
128+
self.root_certs = Some(certs);
129+
self
130+
}
131+
113132
/// Builds the ProverConfig.
114133
pub fn build(self) -> ProverConfig {
115134
ProverConfig {
@@ -122,6 +141,7 @@ impl ProverConfigBuilder {
122141
defer_decryption_from_start: self.defer_decryption_from_start,
123142
network: self.network,
124143
client_auth: self.client_auth,
144+
root_certs: self.root_certs,
125145
}
126146
}
127147
}
@@ -137,6 +157,10 @@ pub struct VerifierConfig {
137157
pub max_sent_records: Option<usize>,
138158
/// Maximum number of received records during online phase.
139159
pub max_recv_records_online: Option<usize>,
160+
/// Custom root certificates (DER-encoded) for TLS server verification.
161+
///
162+
/// If `None`, the Mozilla root certificates are used.
163+
pub root_certs: Option<Vec<Vec<u8>>>,
140164
}
141165

142166
impl Default for VerifierConfig {
@@ -146,6 +170,7 @@ impl Default for VerifierConfig {
146170
max_recv_data: 16384,
147171
max_sent_records: None,
148172
max_recv_records_online: None,
173+
root_certs: None,
149174
}
150175
}
151176
}
@@ -164,6 +189,7 @@ pub struct VerifierConfigBuilder {
164189
max_recv_data: usize,
165190
max_sent_records: Option<usize>,
166191
max_recv_records_online: Option<usize>,
192+
root_certs: Option<Vec<Vec<u8>>>,
167193
}
168194

169195
impl Default for VerifierConfigBuilder {
@@ -173,6 +199,7 @@ impl Default for VerifierConfigBuilder {
173199
max_recv_data: 16384,
174200
max_sent_records: None,
175201
max_recv_records_online: None,
202+
root_certs: None,
176203
}
177204
}
178205
}
@@ -202,13 +229,22 @@ impl VerifierConfigBuilder {
202229
self
203230
}
204231

232+
/// Sets custom root certificates (DER-encoded) for TLS server verification.
233+
///
234+
/// If not set, the Mozilla root certificates are used.
235+
pub fn root_certs(mut self, certs: Vec<Vec<u8>>) -> Self {
236+
self.root_certs = Some(certs);
237+
self
238+
}
239+
205240
/// Builds the VerifierConfig.
206241
pub fn build(self) -> VerifierConfig {
207242
VerifierConfig {
208243
max_sent_data: self.max_sent_data,
209244
max_recv_data: self.max_recv_data,
210245
max_sent_records: self.max_sent_records,
211246
max_recv_records_online: self.max_recv_records_online,
247+
root_certs: self.root_certs,
212248
}
213249
}
214250
}
@@ -240,3 +276,31 @@ pub struct ClientAuth {
240276
/// Client private key (DER encoded).
241277
pub key: Vec<u8>,
242278
}
279+
280+
/// Builds a [`RootCertStore`] from optional DER-encoded root certificates.
281+
///
282+
/// If `root_certs` is `Some`, builds a store from the provided certificates.
283+
/// If `None`, falls back to Mozilla root certificates (requires `mozilla-certs`
284+
/// feature).
285+
pub(crate) fn build_root_store(root_certs: &Option<Vec<Vec<u8>>>) -> Result<RootCertStore> {
286+
match root_certs {
287+
Some(certs) => Ok(RootCertStore {
288+
roots: certs
289+
.iter()
290+
.map(|cert| CertificateDer(cert.clone()))
291+
.collect(),
292+
}),
293+
None => {
294+
#[cfg(feature = "mozilla-certs")]
295+
{
296+
Ok(RootCertStore::mozilla())
297+
}
298+
#[cfg(not(feature = "mozilla-certs"))]
299+
{
300+
Err(SdkError::config(
301+
"no root certificates provided and mozilla-certs feature is not enabled",
302+
))
303+
}
304+
}
305+
}
306+
}

crates/sdk-core/src/prover.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ use tlsn::{
1010
},
1111
connection::ServerName,
1212
prover::{state, Prover, TlsConnection},
13-
webpki::{CertificateDer, PrivateKeyDer, RootCertStore},
13+
webpki::{CertificateDer, PrivateKeyDer},
1414
Session, SessionHandle,
1515
};
1616
use tracing::{error, info};
1717

1818
use crate::{
19-
config::ProverConfig,
19+
config::{build_root_store, ProverConfig},
2020
error::{Result, SdkError},
2121
io::{HyperIo, Io},
2222
types::*,
@@ -170,6 +170,8 @@ impl SdkProver {
170170
));
171171
};
172172

173+
let root_store = build_root_store(&self.config.root_certs)?;
174+
173175
let mut builder = TlsClientConfig::builder()
174176
.server_name(ServerName::Dns(
175177
self.config
@@ -178,7 +180,7 @@ impl SdkProver {
178180
.try_into()
179181
.map_err(|_| SdkError::config("invalid server name"))?,
180182
))
181-
.root_store(RootCertStore::mozilla());
183+
.root_store(root_store);
182184

183185
if let Some(ref client_auth) = self.config.client_auth {
184186
let certs = client_auth

crates/sdk-core/src/verifier.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@ use tlsn::{
55
connection::{ConnectionInfo, ServerName, TranscriptLength},
66
transcript::ContentType,
77
verifier::{state, Verifier},
8-
webpki::RootCertStore,
98
Session, SessionHandle,
109
};
1110
use tracing::info;
1211

1312
use crate::{
14-
config::VerifierConfig,
13+
config::{build_root_store, VerifierConfig},
1514
error::{Result, SdkError},
1615
io::Io,
1716
types::VerifierOutput,
@@ -88,8 +87,9 @@ impl SdkVerifier {
8887
}
8988
});
9089

90+
let root_store = build_root_store(&self.config.root_certs)?;
9191
let verifier_config = tlsn::config::verifier::VerifierConfig::builder()
92-
.root_store(RootCertStore::mozilla())
92+
.root_store(root_store)
9393
.build()
9494
.map_err(|e| SdkError::config(e.to_string()))?;
9595
let verifier = handle

crates/wasm/Cargo.toml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,10 @@ crate-type = ["cdylib", "rlib"]
1616

1717
[features]
1818
default = []
19-
test = []
2019
no-bundler = ["web-spawn/no-bundler"]
2120

2221
[dependencies]
23-
tlsn-core = { workspace = true }
24-
tlsn = { workspace = true, features = ["web", "mozilla-certs"] }
25-
tlsn-sdk-core = { workspace = true, features = ["wasm"] }
26-
tlsn-server-fixture-certs = { workspace = true }
27-
tlsn-tls-core = { workspace = true }
22+
tlsn-sdk-core = { workspace = true, features = ["wasm", "mozilla-certs"] }
2823

2924
console_error_panic_hook = { version = "0.1" }
3025
futures = { workspace = true }

crates/wasm/src/lib.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ pub mod handler;
88
pub(crate) mod io;
99
mod log;
1010
pub mod prover;
11-
#[cfg(feature = "test")]
12-
pub mod tests;
1311
pub mod types;
1412
pub mod verifier;
1513

@@ -18,9 +16,6 @@ pub use log::{LoggingConfig, LoggingLevel};
1816
use wasm_bindgen::prelude::*;
1917
use wasm_bindgen_futures::JsFuture;
2018

21-
#[cfg(feature = "test")]
22-
pub use tests::*;
23-
2419
/// Initializes the module.
2520
#[wasm_bindgen]
2621
pub async fn initialize(

crates/wasm/src/prover/config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@ pub struct ProverConfig {
1414
pub defer_decryption_from_start: Option<bool>,
1515
pub network: NetworkSetting,
1616
pub client_auth: Option<(Vec<Vec<u8>>, Vec<u8>)>,
17+
/// Custom root certificates (DER-encoded) for TLS server verification.
18+
///
19+
/// If not provided, Mozilla root certificates are used.
20+
pub root_certs: Option<Vec<Vec<u8>>>,
1721
}

0 commit comments

Comments
 (0)