Library Contexts
What is a library context?
OpenSSL 3.x introduces OSSL_LIB_CTX — an isolated environment that controls which
cryptographic providers are loaded and used for algorithm fetch. The global default
context is created automatically on the first API call and loads the default provider.
You would need an explicit LibCtx when:
- Running FIPS-validated operations in isolation from non-FIPS ones.
- Building a library that consumes OpenSSL and is supposed to be loaded into other applications
- Loading a non-standard configuration file for one component only.
- Testing — spinning up a context with a known configuration and tearing it down.
LibCtx — library context wrapper
#![allow(unused)]
fn main() {
pub struct LibCtx { /* OSSL_LIB_CTX* */ }
impl LibCtx {
/// Create a new, empty library context.
pub fn new() -> Result<Self, ErrorStack>;
/// Load a named provider into this context.
/// The returned `Provider` handle keeps the provider alive; drop it to unload.
pub fn load_provider(&self, name: &CStr) -> Result<Provider, ErrorStack>;
}
}
LibCtx is Send + Sync. Wrapping it in Arc<LibCtx> lets you share one context
across many threads and algorithm descriptors.
Provider — provider handle
#![allow(unused)]
fn main() {
pub struct Provider { /* OSSL_PROVIDER* */ }
impl Drop for Provider { /* OSSL_PROVIDER_unload */ }
}
Drop the Provider to unload; keep it alive for the duration you need the provider.
FIPS isolation example
#![allow(unused)]
fn main() {
use std::sync::Arc;
use native_ossl::lib_ctx::LibCtx;
use native_ossl::cipher::CipherAlg;
use native_ossl::pkey::Pkey;
// Create an isolated context.
let fips_ctx = Arc::new(LibCtx::new()?);
// FIPS provider: validated algorithm implementations.
// Base provider: encoders/decoders (PEM, DER). Always load it alongside FIPS.
let _fips = fips_ctx.load_provider(c"fips")?;
let _base = fips_ctx.load_provider(c"base")?;
// Fetch algorithms from the FIPS context — only FIPS-approved implementations.
let alg = CipherAlg::fetch_in(&fips_ctx, c"AES-256-GCM", None)?;
// Load a private key bound to the FIPS context.
let key = Pkey::<native_ossl::pkey::Private>::from_pem_in(&fips_ctx, &pem_bytes)?;
}
Keep
_fipsand_basealive for as long as you need the context. In production code, store them in a long-lived struct field alongside theArc<LibCtx>.
How fetch_in works
Every algorithm type (DigestAlg, CipherAlg, MacAlg, KdfAlg, RandAlg) has:
fetch(name, props)— uses the global default context (NULLlibctx).fetch_in(ctx, name, props)— uses the supplied explicit context.
The Arc<LibCtx> is cloned and stored inside the algorithm descriptor, so the context
stays alive as long as the descriptor or any context derived from it is in use.
Property queries
The optional props argument is an OpenSSL property query string. Common values:
| Query string | Effect |
|---|---|
None | No restriction — any matching provider |
c"fips=yes" | FIPS-validated implementations only |
c"fips=no" | Non-FIPS implementations only |
c"provider=default" | Explicit provider name |
#![allow(unused)]
fn main() {
// Fetch only FIPS-approved SHA-256 from the global default context.
let alg = DigestAlg::fetch(c"SHA2-256", Some(c"fips=yes"))?;
}
Thread safety
LibCtx is Send + Sync. All algorithm fetch operations are internally thread-safe;
you may call fetch_in from multiple threads simultaneously on the same Arc<LibCtx>.
Loading configuration files
LibCtx::load_config reads an openssl.cnf-format file and activates any providers
it declares — without touching the global default context:
#![allow(unused)]
fn main() {
let ctx = Arc::new(LibCtx::new()?);
ctx.load_config(Path::new("/etc/myapp/openssl.cnf"))?;
let _prov = ctx.load_provider(c"myprovider")?;
}
PKCS#11 hardware token support
LibCtx::load_pkcs11_provider writes a minimal openssl.cnf snippet to a temporary
file, loads it via load_config, and activates the pkcs11 provider. The temporary
file is deleted before the call returns.
#![allow(unused)]
fn main() {
use std::path::Path;
// Activate pkcs11 provider pointing at the SoftHSM2 PKCS#11 library.
let ctx = Arc::new(LibCtx::new()?);
let _pkcs11 = ctx.load_pkcs11_provider(
Path::new("/usr/lib64/softhsm/libsofthsm2.so"),
)?;
// Now load a private key from the token by URI.
let key = Pkey::<Private>::from_pkcs11_uri(
&ctx,
"pkcs11:token=mytoken;object=mykey;type=private",
)?;
}
The pkcs11 provider (pkcs11-provider.so) must be installed separately; it is not
bundled with OpenSSL. The PKCS#11 library (.so argument) is the underlying hardware
or software token driver.