compat-openssl is a patch-based compatibility workspace for consumers that already depend on openssl and openssl-sys, but need to choose either the upstream OpenSSL implementation or the BoringSSL bindings without renaming those dependencies throughout their graph.
The repository ships two shim crates:
crates/openssl-syspreserves theopenssl-syspackage identity, selects exactly one backend, and relays a curatedDEP_OPENSSL_*metadata contract to downstream build scripts.crates/opensslpreserves theopensslpackage identity and re-exports either the trackedrust-opensslfork orboringbehind the same feature gate.
This repository is intentionally consumed through [patch.crates-io]. Publishing these crates from here is out of scope.
backend-opensslselects the trackedrust-opensslfork.backend-boringselectsboringandboring-sys.- The shim crates default to
backend-boring, so plaincargo buildin this repository exercises the BoringSSL path. - Downstream applications that need deterministic root-controlled backend selection should keep
default-features = falseon patchedopensslandopenssl-sysdependencies and choose a backend explicitly. - Enabling both backends is an error.
- Disabling default features without selecting a backend is an error.
Backend choice belongs at the consumer root so Cargo feature resolution stays deterministic across transitive users such as native-tls.
Patch both crates from this repository and, when you want the application root to control backend selection explicitly, disable dependency defaults and select exactly one backend there:
[features]
default = ["tls-boring"]
tls-openssl = ["openssl/backend-openssl"]
tls-boring = ["openssl/backend-boring"]
[dependencies]
openssl = { version = "0.10.76", default-features = false }
[patch.crates-io]
openssl = { path = "../compat-openssl/crates/openssl" }
openssl-sys = { path = "../compat-openssl/crates/openssl-sys" }If you omit default-features = false on the patched crates, the compatibility shims fall back to backend-boring.
The checked-in example under examples/consumer-app uses the repository-local patch paths that make sense from inside this workspace:
[patch.crates-io]
openssl = { path = "../../crates/openssl" }
openssl-sys = { path = "../../crates/openssl-sys" }Outside this repository, replace those paths with your own checked-out location or a pinned git patch to a revision you control.
If your application or one of its build scripts depends directly on openssl-sys, keep that explicit dependency at the root as well:
[dependencies]
openssl = { version = "0.10.76", default-features = false }
openssl-sys = { version = "0.9.112", default-features = false }That direct openssl-sys dependency is required when a downstream build.rs needs to read DEP_OPENSSL_*, because Cargo only exposes linked-library metadata to immediate dependents of the sys crate.
The OpenSSL backend forwards a curated subset of DEP_REAL_OPENSSL_* keys.
The BoringSSL backend emits an OpenSSL-compatibility profile:
DEP_OPENSSL_INCLUDEcomes fromDEP_BORINGSSL_INCLUDEwhen available, otherwise from${DEP_BORINGSSL_ROOT}/boringssl/include.DEP_OPENSSL_VERSION_NUMBERis synthesized as1010100fto advertise the current OpenSSL 1.1.1 compatibility baseline.DEP_OPENSSL_BACKENDis synthesized asopensslorboringfor diagnostics and fixture validation.
Observed boring-sys metadata uses the DEP_BORINGSSL_* prefix, not DEP_BSSL_*, because the linked backend crate uses links = "boringssl".
The workspace keeps the backend matrix explicit and sequential:
cargo build
just check
just test
just bdd
just examples
just test-allBDD is implemented as a gated integration test at crates/openssl/tests/bdd.rs. It does not run during ordinary crate tests unless explicitly requested through the internal feature gate:
cargo test -p openssl
cargo test -p openssl --no-default-features --features backend-openssl
cargo test -p openssl --test bdd --no-default-features --features backend-openssl,internal-bdd
cargo test -p openssl --test bdd --no-default-features --features backend-boring,internal-bddjust bdd runs the two BDD commands above sequentially.
The standalone example consumer is compiled separately from the workspace because it behaves like a real downstream root package:
cargo build --manifest-path examples/consumer-app/Cargo.toml
cargo build --manifest-path examples/consumer-app/Cargo.toml --no-default-features --features backend-opensslThe acceptance suite exercises real standalone consumers under tests/fixtures/:
downstream-build-metadataverifies the forwardedDEP_OPENSSL_*contract.downstream-native-tlsverifies a transitive safe-layer consumer.downstream-tokio-native-tlsverifies the async wrapper overnative-tls.downstream-reqwest-native-tlsverifies a real HTTP client stack throughreqwestandnative-tls.downstream-postgres-native-tlsverifies a database TLS adapter throughpostgres-native-tls.downstream-openssl-sysverifies a direct raw sys consumer.downstream-openssl-exact-pinverifies patch resolution foropenssl = "=0.10.76".
Each fixture is its own workspace root and patches back to this repository locally.
examples/consumer-app is a standalone consumer crate that demonstrates the currently supported integration surface in one place:
- direct safe-layer usage through
openssl - direct raw-layer usage through
openssl-sys - build-script metadata consumption through
DEP_OPENSSL_* - transitive TLS usage through
native-tls,tokio-native-tls,reqwestwithnative-tls, andpostgres-native-tls
See examples/consumer-app/README.md for the exact dependency list, patch paths, and the local build commands.
- The currently verified compatibility line is
openssl = "0.10.76"andopenssl-sys = "0.9.112". - Plain
cargo buildin the repository root and inexamples/consumer-appdefaults tobackend-boring. - Exact pins must match that mirrored upstream pair; older exact pins require a different maintenance branch or tag.
- Keep the direct
openssl-sysdependency only when you need raw FFI items orDEP_OPENSSL_*inbuild.rs. - The current Boring backend verification matrix does not include
tokio-openssl-based adapters. Those crates expectopenssl::ssl::SslStreammethods such asssl_peek,read_early_data, andwrite_early_datathat are not currently exposed by the Boring-backed safe layer.
- Cargo commands must run sequentially because the workspace and fixtures share cargo caches and lock files.
- The BDD runner also executes fixture builds sequentially with
max_concurrent_scenarios(1). - AST or code-generation tooling is intentionally out of scope unless manual compatibility work becomes the bottleneck.
Apache-2.0