openssl/openssl
EVP
Active contributors: Pauli, Tomas Mraz, slontis, Matt Caswell, Neil Horman
Purpose
EVP is the algorithm-agnostic API in libcrypto. Almost every modern caller — applications, libssl, the openssl CLI — uses it. The pattern: pick an algorithm by name and property, get an opaque handle, drive it via init/update/final.
The EVP layer does not contain algorithm logic. It looks up implementations from providers (see core-and-libctx) and dispatches calls through OSSL_DISPATCH function pointers.
Directory layout
crypto/evp/
├── evp_lib.c 36 KB -- common helpers (size accessors, name lookup, deprecation shims)
├── evp_fetch.c 22 KB -- *_fetch implementations
├── evp_enc.c 47 KB -- EVP_CIPHER_CTX driver
├── digest.c 31 KB -- EVP_MD_CTX driver
├── pmeth_lib.c 43 KB -- EVP_PKEY_CTX (asym ctx) driver
├── m_sigver.c 19 KB -- EVP_DigestSign / EVP_DigestVerify
├── signature.c 42 KB -- EVP_PKEY_sign / EVP_PKEY_verify (one-shot)
├── exchange.c 19 KB -- EVP_PKEY_derive (key exchange)
├── kem.c 17 KB -- EVP_PKEY_encapsulate / EVP_PKEY_decapsulate
├── asymcipher.c 17 KB -- EVP_PKEY_encrypt / EVP_PKEY_decrypt
├── kdf_lib.c, kdf_meth.c -- EVP_KDF
├── mac_lib.c, mac_meth.c -- EVP_MAC
├── evp_rand.c 21 KB -- EVP_RAND
├── keymgmt_lib.c, keymgmt_meth.c, p_lib.c (~68 KB) -- EVP_KEYMGMT and EVP_PKEY
├── skeymgmt_meth.c -- EVP_SKEYMGMT (opaque symmetric keys, 3.4+)
├── evp_pkey.c, evp_pkey_type.c, evp_key.c, p5_crpt*.c, p_legacy.c, m_null.c, m_sigver.c
├── ctrl_params_translate.c 111 KB -- the legacy EVP_PKEY_CTX_ctrl ↔ OSSL_PARAM bridge
├── encode.c -- base64 helpers (legacy EVP_ENCODE_CTX)
├── enc_b64_avx2.c, enc_b64_scalar.c -- the SIMD/scalar base64 cores
├── e_*.c -- backward-compat wrappers around provider-backed ciphers (e_aes.c, e_chacha20_poly1305.c, …)
├── legacy_*.c -- backward-compat wrappers for digests
├── ec_ctrl.c, ec_support.c, dh_ctrl.c, dh_support.c, dsa_ctrl.c -- per-algo controller compatibility
├── pmeth_check.c, pmeth_gn.c -- helpers for params and gen
├── names.c -- name iteration helpers
├── evp_cnf.c -- the [evp_properties] config section
├── evp_local.h, evp_err.c
└── pbe_scrypt.c, p_dec.c, p_enc.c, p_open.c, p_seal.c, p_sign.c, p_verify.c -- legacy convenience helpersAPI surface
graph TB
subgraph Symmetric
MD[EVP_MD<br/>EVP_MD_CTX]
CIP[EVP_CIPHER<br/>EVP_CIPHER_CTX]
MAC[EVP_MAC<br/>EVP_MAC_CTX]
KDF[EVP_KDF<br/>EVP_KDF_CTX]
RAND[EVP_RAND<br/>EVP_RAND_CTX]
SKEY[EVP_SKEY<br/>EVP_SKEYMGMT]
end
subgraph Asymmetric
PKEY[EVP_PKEY<br/>EVP_PKEY_CTX]
KMGMT[EVP_KEYMGMT]
SIG[EVP_SIGNATURE]
KEX[EVP_KEYEXCH]
ASYM[EVP_ASYM_CIPHER]
KEM[EVP_KEM]
end
subgraph Codecs
ENC[EVP_ENCODER]
DEC[EVP_DECODER]
endEach box has a matching *_fetch(libctx, name, props) constructor and a *_free destructor.
Lifecycle pattern (digest example)
EVP_MD *md = EVP_MD_fetch(libctx, "SHA2-256", NULL);
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
EVP_DigestInit_ex2(ctx, md, NULL);
EVP_DigestUpdate(ctx, data, len);
unsigned int dl;
unsigned char digest[EVP_MAX_MD_SIZE];
EVP_DigestFinal_ex(ctx, digest, &dl);
EVP_MD_CTX_free(ctx);
EVP_MD_free(md);The _ex2 form takes OSSL_PARAM arguments. The non-_ex2 forms exist for source compatibility.
EVP_PKEY: a tour
EVP_PKEY is the algorithm-agnostic key handle. It can hold an RSA key, an EC key, an Ed25519 key, an ML-KEM key, or any other public-key thing. Internally it stores either:
- A legacy representation:
RSA *,EC_KEY *, etc. (for backward compatibility with deprecated APIs). - A provider representation: an
EVP_KEYMGMT *and a provider-sidevoid *keydata.
Modern code should always end up in the provider representation. The conversion happens automatically when needed; see crypto/evp/p_lib.c (evp_pkey_downgrade, evp_pkey_upgrade_to_provider, EVP_PKEY_get0_provider, etc.).
The EVP_PKEY_CTX is a per-operation context (sign, verify, derive, encapsulate, encrypt, …). Operations on it use OSSL_PARAM for parameters; the legacy EVP_PKEY_CTX_ctrl API still works for old callers via the translator at crypto/evp/ctrl_params_translate.c. New code should use OSSL_PARAM directly.
Fetch caching
The first EVP_MD_fetch(libctx, "SHA2-256", "fips=yes") builds the handle from scratch. Subsequent fetches return the same cached EVP_MD (with reference count incremented). The cache lives in the per-operation OSSL_METHOD_STORE inside the libctx.
This means an EVP_MD * is safe to share between threads.
Implicit fetching (and why to avoid it)
Calling EVP_DigestInit_ex(ctx, EVP_sha256(), NULL) with the EVP_sha256() macro returns an EVP_MD * from the default libctx using the default properties. This is convenient but bypasses the libctx isolation that the provider model is designed to give you. Prefer:
EVP_MD *md = EVP_MD_fetch(my_libctx, "SHA2-256", "fips=yes");
EVP_DigestInit_ex2(ctx, md, NULL);Legacy compatibility shims
The e_*.c, legacy_*.c, m_null.c, *_ctrl.c, dh_support.c, ec_support.c, dsa_ctrl.c, p_*.c, pbe_scrypt.c, p5_crpt*.c files are mostly backward-compatibility helpers:
e_aes.c,e_chacha20_poly1305.c, etc. expose the oldconst EVP_CIPHER *EVP_aes_256_gcm(void)symbol; internally they fetch from the default provider.legacy_md5.c,legacy_sha.c, etc. do the same for digests.dh_ctrl.c,ec_ctrl.c,dsa_ctrl.ctranslate per-algorithmEVP_PKEY_CTX_ctrlcalls intoOSSL_PARAMfor the new code path.pmeth_*.c,evp_pkey.cwrap the deprecatedEVP_PKEY_METHODstuff.
These exist purely so that pre-3.0 source compiles unchanged. New code never touches them.
ctrl ↔ OSSL_PARAM translator
crypto/evp/ctrl_params_translate.c (111 KB!) is the bridge between the old controller-style API (EVP_PKEY_CTX_ctrl(ctx, type, op, p1, p2)) and the modern parameter API. It contains a per-algorithm switch translating each old controller code into the corresponding OSSL_PARAM. New algorithms should not need additions here.
Integration points
- Above: every public API in
libcrypto's domain libraries (X.509, CMS, OCSP, CMP, …) and the entire TLS/QUIC stack go through EVP for crypto. - Below: EVP fetches from
OSSL_PROVIDERs. The boundary is theOSSL_DISPATCHfunction tables.
Entry points for modification
- Adding a new operation kind (e.g. a brand-new public-key operation): requires extending
core_dispatch.h, adding a fetch function incrypto/evp/evp_fetch.c, adding a method store, and writing implementations. - Adding a new function to an existing operation: extend the
OSSL_FUNC_*ids and update every provider implementation. - Touching the EVP_PKEY implementation:
crypto/evp/p_lib.cis the canonical home.
Documentation
doc/man7/evp.pod— concepts.doc/man3/EVP_DigestInit.pod,EVP_EncryptInit.pod,EVP_PKEY_*.pod— API.doc/man3/EVP_KEYMGMT.pod,EVP_SIGNATURE.pod,EVP_KEYEXCH.pod,EVP_KEM.pod,EVP_ASYM_CIPHER.pod— provider-side primitives.doc/designs/evp_skey.md,doc/designs/evp-cipher-pipeline.md— recent design notes.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.