native-tls

A safe, ergonomic Rust wrapper over each platform's native TLS implementation.

Library
Cargo
v0.2.18
546stars
MIT OR Apache-2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
46/100Fair
Development Activity4
Maintenance20
Community80
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
67/100Good
Architecture80
Code Quality78
Innovation45
Learning Curve65

native-tls gives Rust programs TLS/SSL client and server support without pulling in a single cross-platform crypto stack. Instead, it dispatches at compile time to whatever the operating system already trusts: SChannel on Windows, Secure Transport on macOS, and OpenSSL everywhere else. The public API — TlsConnector, TlsAcceptor, Identity, Certificate — stays identical across all three backends, so application code never branches on platform.

The crate is explicitly secure-by-default rather than a thin pass-through: it enables hostname verification for clients, negotiates strong protocol versions, and exposes builder options (minimum/maximum protocol version, ALPN, disabling verification for testing) without requiring callers to understand each backend’s quirks. Because it reuses the OS-provided TLS stack on Windows and macOS, binaries avoid bundling and statically linking OpenSSL on those platforms, which keeps build times and binary size down and lets certificate trust follow the system’s own CA store and proxy configuration.

What You Get

  • A single TlsConnector/TlsAcceptor API that behaves the same on Windows, macOS, and Linux/BSD despite using three different underlying implementations
  • Secure-by-default configuration: hostname verification for clients, sane cipher/protocol defaults, and explicit opt-in for anything less strict
  • PKCS#12 and X.509/PKCS#8 identity loading for presenting certificates as a TLS server or client
  • min_protocol_version/max_protocol_version builder controls plus optional ALPN negotiation via the alpn and alpn-accept Cargo features
  • Works transparently over any Read + Write stream, so it wraps TcpStream or any other duplex I/O type without extra glue code
  • A vendored feature to statically link a bundled OpenSSL on platforms that use it, when relying on the system OpenSSL isn’t desirable

Common Use Cases

  • Adding TLS client support to a hand-rolled HTTP or protocol client without depending on a full HTTP stack’s bundled TLS choice
  • Building a TLS-terminating server (e.g. a proxy or custom protocol daemon) that accepts client connections over PKCS#12 identities
  • Shipping cross-platform CLI tools or agents that need TLS but must avoid the build overhead of statically linking OpenSSL on Windows/macOS
  • Underpinning higher-level crates (native-tls is used as a pluggable TLS backend by several async runtimes and HTTP clients) that want to defer to whatever TLS the OS already trusts
  • Talking to internal services behind corporate proxies or private CAs where the system certificate store, not a vendored CA bundle, is the source of truth

Under The Hood

Architecture The public surface lives entirely in src/lib.rs, which defines the platform-neutral types (TlsConnector, TlsAcceptor, TlsStream, Identity, Certificate, Error) and then re-exports a single imp module selected at compile time via #[cfg_attr] path attributes — imp/security_framework.rs on Apple targets, imp/schannel.rs on Windows, and imp/openssl.rs everywhere else. Each backend module independently implements the same internal trait-like surface that the public wrappers call into, so adding or changing behavior means touching three parallel files that must stay behaviorally consistent; the public types themselves contain no platform-specific logic, just delegation. This keeps the crate small (roughly 2,500 lines across the four core files) and makes the platform boundary the single place complexity concentrates.

Tech Stack On Apple platforms it depends on security-framework and security-framework-sys plus libc; on Windows, on schannel; on all other Unix-like targets, on openssl, openssl-sys, and openssl-probe, with an optional vendored feature that statically links OpenSSL via the openssl crate’s own vendoring support. tempfile is used on macOS for identity handling and in tests. The crate targets Rust edition 2021 with a pinned MSRV (1.80), and ships no async support directly — async runtimes wrap it themselves.

Code Quality The test suite in src/test.rs is unusually direct: rather than mocking TLS, most tests perform live TLS handshakes against google.com and www.google.com to exercise real protocol-version negotiation, which gives high confidence in actual interop at the cost of requiring network access in CI. CI runs the full matrix (Ubuntu, Windows, macOS) with both --no-default-features --features vendored and --all-features, plus a separate clippy and cargo check pass across iOS and Windows-GNU cross-compilation targets, with RUSTFLAGS=-Dwarnings enforced throughout. The public API returns a typed Result<T, Error> wrapping each backend’s native error rather than swallowing failures, and #![warn(missing_docs)] keeps public-item documentation enforced at compile time.

What Makes It Unique What distinguishes native-tls from pure-Rust alternatives like rustls is the design decision itself: rather than reimplementing TLS in Rust, it treats “whatever TLS the OS already ships and trusts” as the correct default, trading a pure-Rust dependency graph for smaller binaries, faster builds on Windows/macOS, and automatic inheritance of system proxy and CA-store configuration. This is a deliberate, narrow trade-off rather than a novel cryptographic technique, and the crate is honest about that scope — it is an abstraction layer, not a TLS implementation.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search