stalwartlabs/stalwart · critical
Failed to load the platform certificate verifier
Error message
Failed to load the platform certificate verifier
What it means
This panic comes from an .expect() while constructing rustls_platform_verifier::Verifier::new() inside the SHARED_TLS_CONFIGS LazyLock in crates/utils/src/http.rs:72-73. The platform verifier relies on the OS certificate store via rustls-platform-verifier, and fails when that platform verification backend cannot be initialized. Because it runs inside a LazyLock initializer, the panic aborts the process the first time a TLS client config is requested (or at init_shared_tls_configs()).
Source
Thrown at crates/utils/src/http.rs:73
fn verify_tls13_signature(
&self,
_message: &[u8],
_cert: &CertificateDer<'_>,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, TlsError> {
Ok(HandshakeSignatureValid::assertion())
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
self.0.signature_verification_algorithms.supported_schemes()
}
}
static SHARED_TLS_CONFIGS: LazyLock<SharedTlsConfigs> = LazyLock::new(|| {
let provider = Arc::new(aws_lc_rs::default_provider());
let verifier = rustls_platform_verifier::Verifier::new(provider.clone())
.expect("Failed to load the platform certificate verifier");
let mut strict = ClientConfig::builder_with_provider(provider.clone())
.with_safe_default_protocol_versions()
.expect("Failed to build the TLS client configuration")
.dangerous()
.with_custom_certificate_verifier(Arc::new(verifier))
.with_no_client_auth();
strict.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
let mut insecure = ClientConfig::builder_with_provider(provider.clone())
.with_safe_default_protocol_versions()
.expect("Failed to build the TLS client configuration")
.dangerous()
.with_custom_certificate_verifier(Arc::new(NoCertificateVerification(provider)))
.with_no_client_auth();
insecure.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
let mut strict_http1 = strict.clone();View on GitHub (pinned to e962003857)
Solutions
- Install/repair the OS trust store and platform verifier support in the runtime environment (e.g. apt-get install -y ca-certificates on Debian/Ubuntu, apk add ca-certificates on Alpine)
- Initialize the shared TLS config explicitly early in main via init_shared_tls_configs() so the failure surfaces at startup with a clear message rather than lazily mid-request
- If the platform is unsupported, fall back to a rustls WebPkiServerVerifier / webpki-roots-based ClientConfig instead of the platform verifier
- Check the binary targets a supported OS/arch and that the rustls-platform-verifier crate version supports the target platform
Example fix
// before
let verifier = rustls_platform_verifier::Verifier::new(provider.clone())
.expect("Failed to load the platform certificate verifier");
// after
let verifier = match rustls_platform_verifier::Verifier::new(provider.clone()) {
Ok(v) => v,
Err(e) => {
log::warn!("platform verifier unavailable ({e}); using webpki roots fallback");
build_webpki_fallback_verifier(provider.clone())
}
}; Defensive patterns
Strategy: fallback
Validate before calling
// probe once at startup:
fn platform_verifier_ok() -> bool {
rustls_platform_verifier::Verifier::new(Arc::new(aws_lc_rs::default_provider())).is_ok()
} Try / catch
// Rust panics are not try/catch-able normally; force the LazyLock at startup
// and use catch_unwind plus a webpki-roots fallback config when needed:
let ok = std::panic::catch_unwind(init_shared_tls_configs).is_ok();
let config = if ok { shared_tls_config(false) } else { fallback_webpki_roots_config() }; Prevention
- Install ca-certificates / the OS trust store in every container image (apt-get install -y ca-certificates or apk add ca-certificates)
- Call init_shared_tls_configs() at process start so failures happen deterministically at boot, not on first request
- Test the binary on the exact deployment target OS/arch (base image, musl/glibc) in CI
- Provide a webpki-roots fallback path for platforms the platform verifier does not support
When it happens
Trigger: Calling init_shared_tls_configs() or shared_tls_config() (which forces the LazyLock) on a system where rustls_platform_verifier::Verifier::new() cannot load the OS trust store / verifier backend, e.g. minimal Docker images lacking platform verifier support, unsupported OS targets, or a broken system certificate service.
Common situations: Running in scratch/alpine/musl Docker images without ca-certificates or the platform verifier proxy; cross-compiled binaries on an OS the crate does not support; hardened/sandboxed environments (no DBus on Linux, restricted macOS Security.framework); tests in minimal CI containers.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Failed to build the TLS client configuration
- unwrap_tls called on non-TLS acceptor
- failed to install aws-lc-rs as the default rustls crypto pro
- Failed to read {yaml_path:?}
- Node id {node_id} exceeds {MAX_NODE_ID}, panicking to avoid
AI-assisted analysis of stalwartlabs/stalwart@e962003857 (2026-09-06).
Data as JSON: /api/errors/53dd7bfbc17f2fe2.
Report an issue: GitHub.