openssl/openssl
Core and library contexts
Active contributors: Pauli, Tomas Mraz, Matt Caswell, slontis, Neil Horman
Purpose
The "core" of libcrypto is the small set of subsystems that knows how to find an algorithm implementation in a sea of providers and bind it to a usable handle. Everything in OpenSSL that operates on cryptographic data ultimately reaches into this code path.
There are five intertwined pieces:
OSSL_LIB_CTX— a library context. The "world" that providers, properties, and per-context state live in.- Namemap — a bidirectional table mapping algorithm names (and aliases, OIDs, …) to integer ids.
- Property store — a parsed/optimized representation of property strings like
provider=fips,fips=yes. - Fetch — the algorithm lookup machinery.
EVP_*_fetch(libctx, "name", "props"). - Provider object — the runtime view of a loaded provider, including its dispatch table and teardown.
Directory layout
crypto/
├── context.c -- OSSL_LIB_CTX_new/free, per-libctx data registry
├── init.c, initthread.c -- one-time init, thread-stop callbacks
├── defaults.c -- default property handling
├── core_namemap.c -- the namemap
├── core_algorithm.c -- algorithm cache helpers
├── core_fetch.c -- the fetch implementation
├── property/ -- property string parser, query matcher, definition cache
│ ├── property.h, property_local.h
│ ├── property_parse.c, property_lookup.c
│ ├── property_string.c, property_query.c
│ └── defn_cache.c
├── provider.c -- public OSSL_PROVIDER API
├── provider_core.c -- 84 KB: the provider state machine, dispatch resolution
├── provider_conf.c -- openssl.cnf [providers] section parser
├── provider_child.c -- nested-libctx support (for FIPS internal libctx)
├── provider_predefined.c -- the four built-in providers (default/base/legacy/null) registry
└── provider_local.hPublic headers: include/openssl/crypto.h.in (the OSSL_LIB_CTX API), include/openssl/core.h, core_dispatch.h, core_names.h.in, core_object.h, provider.h.
Key abstractions
| Type | What it is | Where |
|---|---|---|
OSSL_LIB_CTX |
The container for everything below. | crypto/context.c |
OSSL_PROVIDER |
A loaded provider's runtime handle. | crypto/provider_core.c |
OSSL_NAMEMAP |
Per-libctx name↔id table. | crypto/core_namemap.c |
OSSL_PROPERTY_LIST |
A parsed property query. | crypto/property/property_parse.c |
OSSL_METHOD_STORE |
Per-operation cache of (name id, property, provider) → method. | crypto/property/property.c |
OSSL_DISPATCH |
{function_id, function_pointer} pair (from core.h). |
include/openssl/core.h |
OSSL_ALGORITHM |
A row published by a provider: {names, properties, dispatch, description}. |
include/openssl/core.h |
Each subsystem in libcrypto (EVP_MD, EVP_CIPHER, EVP_KEYMGMT, etc.) maintains its own OSSL_METHOD_STORE keyed by the operation id (OSSL_OP_DIGEST, OSSL_OP_CIPHER, …) so that fetch results are cached.
How fetch works
sequenceDiagram
participant Caller
participant EVP as EVP_MD_fetch
participant MS as OSSL_METHOD_STORE
participant NM as OSSL_NAMEMAP
participant PS as Property store
participant PROV as OSSL_PROVIDER
Caller->>EVP: EVP_MD_fetch(libctx, "SHA2-256", "fips=yes")
EVP->>NM: name -> id
EVP->>PS: parse "fips=yes"
EVP->>MS: lookup (id, props) hit?
alt cache hit
MS-->>EVP: cached EVP_MD
else miss
EVP->>PROV: for each provider: query OSSL_OP_DIGEST table
PROV-->>EVP: OSSL_ALGORITHM[] (rows include their property defs)
EVP->>PS: match each row's property def vs. query
EVP->>EVP: build EVP_MD bound to chosen dispatch table
EVP->>MS: cache (id, props) -> method
end
EVP-->>Caller: EVP_MD *Code path:
crypto/evp/evp_fetch.c:evp_generic_fetch()is the per-operation entry point. It callsinner_evp_generic_fetch(), which goes throughOSSL_method_construct()incrypto/core_fetch.c.OSSL_method_constructwalks the loaded providers in the libctx viaprovider_iter, calls each one'sOSSL_FUNC_provider_query_operationto get theOSSL_ALGORITHM[], and asks the per-operation method store to install it.- The method store filters by property using
crypto/property/property_query.c.
Library context lifecycle
OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
OSSL_PROVIDER *fips = OSSL_PROVIDER_load(libctx, "fips");
OSSL_PROVIDER *base = OSSL_PROVIDER_load(libctx, "base");
EVP_set_default_properties(libctx, "?fips=yes");
EVP_MD *md = EVP_MD_fetch(libctx, "SHA2-256", NULL);
/* ... use md ... */
EVP_MD_free(md);
OSSL_LIB_CTX_free(libctx); /* unloads providers, releases caches */NULL for libctx means "the implicit default context"; OSSL_LIB_CTX_get0_default() returns its handle. The default context is initialised on first use.
Per-libctx data
Subsystems register a slot in the libctx's per-context data table during init. The pattern, from many _init.c files:
static void *foo_ctx_new(OSSL_LIB_CTX *libctx) { /* alloc state */ }
static void foo_ctx_free(void *vctx) { /* free state */ }
static const OSSL_LIB_CTX_METHOD foo_method = {
OSSL_LIB_CTX_METHOD_PRIORITY_2,
foo_ctx_new, foo_ctx_free,
};
void *ossl_foo_ctx_get(OSSL_LIB_CTX *libctx)
{
return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_FOO_INDEX, &foo_method);
}The slot indices are enumerated in crypto/context.c. The mechanism keeps subsystems decoupled (no global init order, no global state).
Properties
A property string is a comma-separated list of key=value (or ?key=value for "soft" — preferred but not required). Examples:
| Query | Meaning |
|---|---|
provider=default |
Only algorithms registered with provider=default. |
fips=yes |
Hard requirement. |
?fips=yes |
Prefer fips=yes if available, fall back otherwise. |
provider=fips,fips=yes |
Compose constraints. |
provider!=legacy |
Exclude legacy. |
Parsing lives in crypto/property/property_parse.c; matching in property_query.c. The grammar is described at the top of the parser file and in doc/man7/property.pod.
Default property
Every libctx has a "default property query" — applied when the caller doesn't pass one. Set via EVP_set_default_properties() (or in openssl.cnf).
Provider objects
crypto/provider_core.c is by far the largest file in the core (84 KB). It owns:
- The list of providers per libctx.
- Each provider's
OSSL_DISPATCHtables (the core directions, exposing libctx services to the provider, and the provider directions, exposing algorithms to libcrypto). - Activation reference counts (you can
OSSL_PROVIDER_load/unloadrepeatedly). - The
OSSL_PROVIDER_set_default_search_pathmechanism for finding.somodules. - Hooks for child-libctx propagation (used by FIPS to spawn an internal libctx for its own algorithms).
The provider configuration via openssl.cnf is parsed by crypto/provider_conf.c, which interprets [providers], [default_sect], etc. and calls into the provider load path.
Initialization
crypto/init.c and crypto/initthread.c implement OPENSSL_init_crypto() (the public initialiser) and the per-thread cleanup hooks. The library uses one-time init (CRYPTO_THREAD_run_once) for everything; explicit init is rarely needed.
Integration points
- Every EVP API routes through this code on first use of an algorithm in a libctx.
- Providers call back into core via the dispatch table they receive in
OSSL_provider_initto register names, allocate per-context data, query parameters, etc. apps/opensslusesapps/lib/app_libctx.cto maintain the CLI's libctx and apply-provider/-propqueryoptions.
Entry points for modification
- Adding a per-libctx state slot: register a new
OSSL_LIB_CTX_*_INDEXincrypto/context.cwith anew/freemethod. - Touching the property syntax:
crypto/property/property_parse.c. Consider how it interacts withprovider=…matching inproperty_query.c. - Touching the provider load path:
crypto/provider_core.c,crypto/provider_conf.c. Be careful with reference counting — providers can be loaded multiple times.
Documentation
doc/man7/crypto.pod— concepts.doc/man7/provider.pod— provider authoring.doc/man7/property.pod— property syntax.doc/man3/OSSL_LIB_CTX.pod,OSSL_PROVIDER.pod,EVP_MD_fetch.pod, etc.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.