PROVIDER-DIGEST(7SSL)

🌸 provider-digest(7SSL) 🌸

okay bestie sit DOWN because we're reading provider-digest(7SSL), and it's genuinely one of the most important pages in the whole OpenSSL provider saga πŸ’–

this is the page that explains how a digest β€” you know, your SHA-2s, your SHAKEs, your "turn a big thing into a small fixed thing" girlies β€” gets plugged into the provider system. specifically, it's about the holy handshake between the digest library and a provider. the library side says "hey, give me a digest", and the provider side goes "say less, here's my function table" ✨

think of it like this: the provider doesn't hand you an object, it hands you a dispatch table full of function pointers, and every one of those pointers has a name that starts with OSSL_FUNC_digest_. this page is the guest list for that party. no cap. πŸŽ€


πŸ‘‘ NAME πŸ‘‘

provider-digest β€” the digest library <-> provider functions πŸ¦‹

like, literally the bridge between those two things. that's the whole vibe. the library wants a digest, the provider has a digest, and this page is the contract they both signed. πŸ’…


✨ SYNOPSIS ✨

bestie this is not a real header file you compile against as-is. these are function signatures that show up in OSSL_DISPATCH arrays. the page is very explicit about that and so am I. do not βœ‹ try to #include your way into calling these directly, that's not the move πŸ™ˆ
#include <openssl/core_dispatch.h>
#include <openssl/core_names.h>

/*
 * Digests support the following function signatures in OSSL_DISPATCH arrays.
 * (The function signatures are not actual functions).
 */

/* Context management */
void *OSSL_FUNC_digest_newctx(void *provctx);
void OSSL_FUNC_digest_freectx(void *dctx);
void *OSSL_FUNC_digest_dupctx(void *dctx);
void OSSL_FUNC_digest_copyctx(void *voutctx, void *vinctx);

/* Digest generation */
int OSSL_FUNC_digest_init(void *dctx, const OSSL_PARAM params[]);
int OSSL_FUNC_digest_update(void *dctx, const unsigned char *in, size_t inl);
int OSSL_FUNC_digest_final(void *dctx, unsigned char *out, size_t *outl,
                           size_t outsz);
int OSSL_FUNC_digest_digest(void *provctx, const unsigned char *in, size_t inl,
                            unsigned char *out, size_t *outl, size_t outsz);

/* Digest state serialization */
int OSSL_FUNC_digest_serialize(void *dctx, unsigned char *out, size_t *outl);
int OSSL_FUNC_digest_deserialize(void *dctx, const unsigned char *in, size_t inl);

/* Digest parameter descriptors */
const OSSL_PARAM *OSSL_FUNC_digest_gettable_params(void *provctx);

/* Digest operation parameter descriptors */
const OSSL_PARAM *OSSL_FUNC_digest_gettable_ctx_params(void *dctx,
                                                       void *provctx);
const OSSL_PARAM *OSSL_FUNC_digest_settable_ctx_params(void *dctx,
                                                       void *provctx);

/* Digest parameters */
int OSSL_FUNC_digest_get_params(OSSL_PARAM params[]);

/* Digest operation parameters */
int OSSL_FUNC_digest_set_ctx_params(void *dctx, const OSSL_PARAM params[]);
int OSSL_FUNC_digest_get_ctx_params(void *dctx, OSSL_PARAM params[]);

quick vibe check on what you're looking at up there: six little cliques of functions, all living under the digest umbrella 🫢

  • Context management β€” newctx, freectx, dupctx, copyctx. the "make me a lil guy / yeet the lil guy / clone the lil guy" crew πŸ’€
  • Digest generation β€” init, update, final, digest. the actual crunching. the main characters, honestly πŸ‘‘
  • Digest state serialization β€” serialize, deserialize. saving and loading the lil guy's soul ✨
  • Digest parameter descriptors β€” gettable_params. "what can you tell me about yourself" energy πŸŽ€
  • Digest operation parameter descriptors β€” gettable_ctx_params, settable_ctx_params. "what can I read/write on a live operation" πŸ¦‹
  • Digest parameters β€” get_params. the static stats, not tied to any one context 🌸
  • Digest operation parameters β€” set_ctx_params, get_ctx_params. the live, per-operation knobs πŸ’…

and that's where part 1 leaves us, bestie. the rest is coming β€” don't go anywhere πŸ’œ

πŸ’– DESCRIPTION πŸ’–

okay so bestie, this whole page is for provider authors β€” the devs writing providers, iykyk. if you're not one, go peek at provider(7) first, it'll catch you up. 🫢

The DIGEST operation is how providers implement digest algorithms and drop them into the hands of applications through the API functions EVP_DigestInit_ex(3), EVP_DigestUpdate(3) and EVP_DigestFinal(3) (plus all their little related function friends).

Every "function" we gossip about here is actually passed as a function pointer, dying back and forth between libcrypto and the provider inside OSSL_DISPATCH(3) arrays, which ride in via OSSL_ALGORITHM(3) arrays that the provider's provider_query_operation() function hands back (scroll to "Provider Functions" in provider-base(7) for the tea).

Every one of these "functions" has a matching function type definition named OSSL_FUNC_{name}_fn, and a lil helper function that fetches the function pointer out of an OSSL_DISPATCH(3) element, named OSSL_FUNC_{name}. for example, the "function" OSSL_FUNC_digest_newctx() comes with exactly these:

 typedef void *(OSSL_FUNC_digest_newctx_fn)(void *provctx);
 static ossl_inline OSSL_FUNC_digest_newctx_fn
     OSSL_FUNC_digest_newctx(const OSSL_DISPATCH *opf);

OSSL_DISPATCH(3) arrays are indexed by numbers, and those numbers live as macros in openssl-core_dispatch.h(7), like this:

 OSSL_FUNC_digest_newctx               OSSL_FUNC_DIGEST_NEWCTX
 OSSL_FUNC_digest_freectx              OSSL_FUNC_DIGEST_FREECTX
 OSSL_FUNC_digest_dupctx               OSSL_FUNC_DIGEST_DUPCTX
 OSSL_FUNC_digest_copyctx              OSSL_FUNC_DIGEST_COPYCTX

 OSSL_FUNC_digest_init                 OSSL_FUNC_DIGEST_INIT
 OSSL_FUNC_digest_update               OSSL_FUNC_DIGEST_UPDATE
 OSSL_FUNC_digest_final                OSSL_FUNC_DIGEST_FINAL
 OSSL_FUNC_digest_digest               OSSL_FUNC_DIGEST_DIGEST

 OSSL_FUNC_digest_serialize            OSSL_FUNC_DIGEST_SERIALIZE
 OSSL_FUNC_digest_deserialize          OSSL_FUNC_DIGEST_DESERIALIZE

 OSSL_FUNC_digest_get_params           OSSL_FUNC_DIGEST_GET_PARAMS
 OSSL_FUNC_digest_get_ctx_params       OSSL_FUNC_DIGEST_GET_CTX_PARAMS
 OSSL_FUNC_digest_set_ctx_params       OSSL_FUNC_DIGEST_SET_CTX_PARAMS

 OSSL_FUNC_digest_gettable_params      OSSL_FUNC_DIGEST_GETTABLE_PARAMS
 OSSL_FUNC_digest_gettable_ctx_params  OSSL_FUNC_DIGEST_GETTABLE_CTX_PARAMS
 OSSL_FUNC_digest_settable_ctx_params  OSSL_FUNC_DIGEST_SETTABLE_CTX_PARAMS

a digest algorithm implementation doesn't have to implement all of these, bestie. but to actually be usable, you need all or none of OSSL_FUNC_digest_newctx, OSSL_FUNC_digest_freectx, OSSL_FUNC_digest_init, OSSL_FUNC_digest_update, OSSL_FUNC_digest_final and OSSL_FUNC_digest_get_params. everything else? optional, do what you want. πŸ’…


πŸŽ€ Context Management Functions πŸŽ€

  • OSSL_FUNC_digest_newctx() β€” should create and return a pointer to a provider-side structure that holds context info during a digest operation. that pointer gets passed back into a bunch of the other digest operation function calls. the provctx parameter is the provider context made during provider initialisation (see provider(7)).
  • OSSL_FUNC_digest_freectx() β€” gets handed a pointer to the provider-side digest context in the dctx parameter. this function should free every resource tied to that context.
  • OSSL_FUNC_digest_dupctx() β€” should duplicate the provider-side digest context in the dctx parameter and return the duplicate copy. ✨
  • OSSL_FUNC_digest_copyctx() β€” should copy the provider-side digest context in the vinctx parameter over to the voutctx parameter, which is, like, another provider-side context. the OSSL_FUNC_digest_copyctx function gets used inside the EVP_MD_CTX_copy_ex function to speed up HMAC operations in the PBKDF2. this one's optional, and dupctx will be used if there's no EVP_MD_CTX_copy_ex function.

🌸 Digest Generation Functions 🌸

  • OSSL_FUNC_digest_init() β€” initialises a digest operation given a freshly created provider-side digest context in the dctx parameter. the params, if it's not NULL, should be set on the context in a way similar to using OSSL_FUNC_digest_set_ctx_params().
  • OSSL_FUNC_digest_update() β€” gets called to feed in data to be digested, as part of a digest operation that was already initialised. the dctx parameter holds a pointer to a previously initialised provider-side context. OSSL_FUNC_digest_update() should digest inl bytes of data sitting at the location in points to. and it's totally fine to call OSSL_FUNC_digest_update() multiple times for one single digest operation. πŸ”₯
  • OSSL_FUNC_digest_final() β€” generates a digest that was started via earlier OSSL_FUNC_digest_init() and OSSL_FUNC_digest_update() calls. the dctx parameter holds a pointer to the provider-side context. the digest should be written to *out and the length of the digest to *outl. and fr, the digest must not exceed outsz bytes.
  • OSSL_FUNC_digest_digest() β€” this one's a "oneshot" digest function, no cap. no provider-side digest context gets used at all. instead, the provider context created during provider initialisation is passed in the provctx parameter (see provider(7)). inl bytes at in should be digested, and the result stored at out. the length of the digest goes into *outl, which should not exceed outsz bytes.

πŸ¦‹ Digest State Serialization Functions πŸ¦‹

OSSL_FUNC_digest_serialize() serializes the state of the digest context dctx. if out is NULL, then the maximum necessary size for the output buffer gets written to *outl. if out is not NULL, then *outl is assumed to already contain the length of the out buffer. if the call succeeds, the serialized data is written to out and however much data was written gets stored in *outl. ✨

OSSL_FUNC_digest_deserialize() deserializes the data from in, of size inlen, into the digest context dctx. the context dctx should be initialized before you call this function. after a successful deserialization, the context is ready to be used for any subsequent digest operations. πŸ’…

the content of the state and its validity (over time, process lifetime, etc.) are completely in the control of the provider. the docs for each provider should state exactly what guarantees it can offer when it comes to recovering the state of a serialized blob.

πŸ’œ Digest Parameters πŸ’œ

peep OSSL_PARAM(3) for more details on the parameters structure these functions use.

  • OSSL_FUNC_digest_get_params() β€” gets the details of the algorithm implementation and stores them in params.
  • OSSL_FUNC_digest_set_ctx_params() β€” sets digest operation parameters for the provider-side digest context dctx to params. any parameter settings are additional to whatever was previously set. passing NULL for params should return true.
  • OSSL_FUNC_digest_get_ctx_params() β€” gets digest operation details from the given provider-side digest context dctx and stores them in params. passing NULL for params should return true.
  • OSSL_FUNC_digest_gettable_params() β€” returns a constant OSSL_PARAM(3) array holding descriptors of the parameters that OSSL_FUNC_digest_get_params() can handle.
  • OSSL_FUNC_digest_gettable_ctx_params() and OSSL_FUNC_digest_settable_ctx_params() β€” both return constant OSSL_PARAM(3) arrays as descriptors of the parameters that OSSL_FUNC_digest_get_ctx_params() and OSSL_FUNC_digest_set_ctx_params() can handle, respectively. the array is based on the current state of the provider-side context if dctx is not NULL, and on the provider-side algorithm provctx otherwise.

the parameters currently recognised by built-in digests with this function are as follows. heads up: not all parameters are relevant to, or understood by, all digests. πŸ™ˆ

  • "blocksize" (OSSL_DIGEST_PARAM_BLOCK_SIZE) <unsigned integer> β€” the digest block size. the length of the "blocksize" parameter should not exceed that of a size_t.
  • "size" (OSSL_DIGEST_PARAM_SIZE) <unsigned integer> β€” the digest output size. the length of the "size" parameter should not exceed that of a size_t.
  • "flags" (OSSL_DIGEST_PARAM_FLAGS) <unsigned integer> β€” diverse flags describing exceptional behaviour for the digest:
    • EVP_MD_FLAG_ONESHOT β€” this digest method can only handle one block of input.
    • EVP_MD_FLAG_XOF β€” this digest method is an extensible-output function (XOF).
    • EVP_MD_FLAG_DIGALGID_NULL β€” when setting up a DigestAlgorithmIdentifier, this flag will have the parameter set to NULL by default. use this for PKCS#1. note: if combined with EVP_MD_FLAG_DIGALGID_ABSENT, the latter will override.
    • EVP_MD_FLAG_DIGALGID_ABSENT β€” when setting up a DigestAlgorithmIdentifier, this flag will have the parameter left absent by default. note: if combined with EVP_MD_FLAG_DIGALGID_NULL, the latter will be overridden.
    • EVP_MD_FLAG_DIGALGID_CUSTOM β€” custom DigestAlgorithmIdentifier handling via ctrl, with EVP_MD_FLAG_DIGALGID_ABSENT as default. note: if combined with EVP_MD_FLAG_DIGALGID_NULL, the latter will be overridden. currently unused.

the length of the "flags" parameter should equal that of an unsigned long int.


πŸ‘‘ Digest Context Parameters πŸ‘‘

OSSL_FUNC_digest_set_ctx_params() sets digest parameters associated with the given provider-side digest context dctx to params. any parameter settings are additional to any that were previously set. see OSSL_PARAM(3) for further details on the parameters structure. πŸ’–

OSSL_FUNC_digest_get_ctx_params() gets details of the currently set parameter values associated with the give provider-side digest context dctx and stores them in params. see OSSL_PARAM(3) for further details on the parameters structure.

the OpenSSL FIPS provider supports the following gettable context parameter:

  • "fips-indicator" (OSSL_DIGEST_PARAM_FIPS_APPROVED_INDICATOR) <integer> β€” returns 1 if the operation is FIPS approved, or 0 otherwise. see "FIPS indicators" in fips_module(7) for more information. βœ…

⭐ RETURN VALUES ⭐

OSSL_FUNC_digest_newctx() and OSSL_FUNC_digest_dupctx() should return the newly created provider-side digest context, or NULL on failure. 😭

OSSL_FUNC_digest_init(), OSSL_FUNC_digest_update(), OSSL_FUNC_digest_final(), OSSL_FUNC_digest_digest(), OSSL_FUNC_digest_get_params(), OSSL_FUNC_digest_set_ctx_params(), OSSL_FUNC_digest_get_ctx_params(), OSSL_FUNC_digest_serialize(), and OSSL_FUNC_digest_deserialize() should return 1 for success or 0 on error. periodt.

OSSL_FUNC_digest_size() should return the digest size.

OSSL_FUNC_digest_block_size() should return the block size of the underlying digest algorithm.


πŸ’€ BUGS πŸ’€

okay so this is a real one, bestie: the EVP_Q_digest(), EVP_Digest() and EVP_DigestFinal_ex() API calls do not expect the digest size to be larger than EVP_MAX_MD_SIZE. any algorithm that produces bigger digests is literally unusable with those API calls. πŸ’€ no cap.

πŸ‘€ SEE ALSO β€” the bestie recommendations ✨

okay so if this page ate and you want more, these are the icons you should also be reading, fr fr:

(yes literally all of them, go read, it's giving ✨ research era ✨)


πŸ“œ HISTORY β€” the lore πŸ’–

  • the whole provider DIGEST interface? introduced in OpenSSL 3.0. iconic debut, no notes.
  • OSSL_FUNC_digest_copyctx() slid in later, in the 3.5 version. late arrival but so valid.
  • the "fips-indicator" context parameter? that's an OpenSSL 4.0 addition. newest baby in the family 🍼

Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved.

Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at <https://www.openssl.org/source/license.html>.


okay bestie that's the whole page, we made it, you're officially a digest provider expert now πŸ’…πŸ‘‘

this fine piece of documentation is straight from OpenSSL 4.0.3, dated 2026-09-29, and it lives at the manpage address PROVIDER-DIGEST(7SSL). go forth and hash responsibly πŸ¦‹βœ¨πŸŒΈ

πŸ“¦ where this page comes from