CRYPTO_SET_EX_DATA(3)
π NAME π
okay so bestie, welcome to the CRYPTO_SET_EX_DATA(3) page from the Library Functions Manual β this is all about low-level functions for application specific data π«Ά.
The whole squad is: CRYPTO_get_ex_new_index, CRYPTO_EX_new, CRYPTO_EX_free, CRYPTO_EX_dup, CRYPTO_new_ex_data, CRYPTO_set_ex_data, CRYPTO_get_ex_data, CRYPTO_free_ex_data, and CRYPTO_cleanup_all_ex_data. β¨
π SYNOPSIS π
You're pulling from the library libcrypto, and you need this include:
#include <openssl/crypto.h>
Then the function tea is exactly this, no cap:
int
CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
CRYPTO_EX_free *free_func);
typedef int
CRYPTO_EX_new(void *parent, void *data, CRYPTO_EX_DATA *ad, int idx,
long argl, void *argp);
typedef void
CRYPTO_EX_free(void *parent, void *data, CRYPTO_EX_DATA *ad, int idx,
long argl, void *argp);
typedef int
CRYPTO_EX_dup(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from,
void *datap, int idx, long argl, void *argp);
int
CRYPTO_new_ex_data(int class_index, void *parent, CRYPTO_EX_DATA *ad);
int
CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *data);
void *
CRYPTO_get_ex_data(CRYPTO_EX_DATA *ad, int idx);
void
CRYPTO_free_ex_data(int class_index, void *parent, CRYPTO_EX_DATA *ad);
void
CRYPTO_cleanup_all_ex_data(void);
π DESCRIPTION π
So the library implements the functions documented in the RSA_get_ex_new_index(3) manual page β plus the similar functions for other parent object types β by using the functions documented right here. And listen: application programs almost never need to call the functions on this page directly. Like, almost never-ever. π
CRYPTO_get_ex_new_index() behaves in the same way as RSA_get_ex_new_index(3) except that the parent object type that the new idx is reserved for is not part of the function name. Instead, it's specified by the additional class_index argument, which receives one of the CRYPTO_EX_INDEX_* constants defined in <openssl/crypto.h>. The recommendation given in RSA_get_ex_new_index(3) to set the argl argument to 0 and the last four arguments all to NULL applies. The library passes the argl and argp arguments through to the callback functions for the respective idx, but ignores them otherwise.
If a function pointer is passed for the new_func argument, that function is called for the returned idx whenever a new parent object is allocated with RSA_new(3) or a similar function. π
If a function pointer is passed for the free_func argument, that function is called for the returned idx when a parent object is freed with RSA_free(3) or a similar function.
β¨ the new_func and free_func arguments β¨
The arguments of new_func and free_func are as follows:
parentβ the parent object that contains the datadataβ the data previously set byCRYPTO_set_ex_data()atidxinparentadβ theCRYPTO_EX_DATAsubobject of the parent objectidxβ return value ofCRYPTO_get_ex_new_index()that set this callbackarglβ thearglpassed toCRYPTO_get_ex_new_index()for thisidxargpβ theargppassed toCRYPTO_get_ex_new_index()for thisidx
π¦ the dup_func situation π¦
If a function pointer is passed for the dup_func, that function is supposed to be called for the returned idx whenever a parent object of the respective type is copied. Actually, the only functions doing that are BIO_dup_chain(3), EC_KEY_copy(3), and SSL_dup(3), and the TLS 1.3 network stack does it internally when duplicating a SSL_SESSION object after receiving a new session ticket message. Most other object types supporting ex_data do not support copying in the first place, whereas DSA_dup_DH(3) and X509_dup(3) simply ignore dup_func. π
The arguments of dup_func are as follows:
toβ theCRYPTO_EX_DATAsubobject of the new parent objectfromβ theCRYPTO_EX_DATAsubobject of the original parent objectdatapβ a pointer to a copy of the pointer to the original ex_dataidxβ return value ofCRYPTO_get_ex_new_index()that set this callbackarglβ thearglpassed toCRYPTO_get_ex_new_index()for thisidxargpβ theargppassed toCRYPTO_get_ex_new_index()for thisidx
Inside dup_func, the data pointer contained in the original parent object being copied can be accessed by casting and dereferencing datap, for example:
char *orig_data = *(char **)datap;
If the original data is copied, for example in a manner similar to
char *new_data;
if ((new_data = strdup(orig_data)) == NULL)
return 0;
then the pointer to the newly allocated memory needs to be passed back to the caller in the datap argument, for example:
*(char **)datap = new_data;
return 1;
Calling CRYPTO_set_ex_data(to, idx, new_data) from inside dup_func has no effect because the code calling dup_func unconditionally calls CRYPTO_set_ex_data(to, idx, *datap) after dup_func returns successfully. Consequently, if dup_func does not change *datap, the new parent object ends up containing a pointer to the same memory as the original parent object and any memory allocated in dup_func is leaked. π¨ not the vibe, bestie β that's a leak.
When multiple callback functions are called, they are called in increasing order of their idx value.
CRYPTO_new_ex_data() is an internal function that initializes the ad subobject of the parent object, with the type of the parent object specified by the class_index argument. Initialization includes calling the respective new_func callbacks for all reserved idx values that have such callbacks configured. Despite its name, CRYPTO_new_ex_data() does not create a new object but requires that ad points to an already allocated but still uninitialized object. π
CRYPTO_set_ex_data() and CRYPTO_get_ex_data() behave in the same way as RSA_set_ex_data(3) and RSA_get_ex_data(3), respectively, except that they do not accept a pointer to the parent object but instead require a pointer to the CRYPTO_EX_DATA subobject of that parent object.
CRYPTO_free_ex_data() is an internal function that frees any memory used inside the ad subobject of the parent object, with the type of the parent object specified by the class_index argument. This includes calling the respective free_func callbacks for all reserved idx values that have such callbacks configured. Despite its name, CRYPTO_free_ex_data() does not free ad itself. π§
π¨ bestie, CRYPTO_cleanup_all_ex_data() is deprecated and has no effect. It is retained for source and binary compatibility only. Application programs should not call it after individual operations, from individual library components, or during process shutdown. No replacement call is needed.
In particular, OPENSSL_cleanup(3) is not a replacement for CRYPTO_cleanup_all_ex_data(). It tears down process-wide library state and is only intended for final shutdown after all threads using libcrypto have stopped.
π RETURN VALUES π
CRYPTO_get_ex_new_index() returns a new index equal to or greater than 1 or -1 if memory allocation fails.
CRYPTO_EX_new() and CRYPTO_EX_dup() functions are supposed to return 1 on success or 0 on failure.
CRYPTO_new_ex_data() and CRYPTO_set_ex_data() return 1 on success or 0 if memory allocation fails.
CRYPTO_get_ex_data() returns the application specific data or NULL if the parent object that contains ad does not contain application specific data at the given idx. π«Ά
π ERRORS π
After failure of CRYPTO_get_ex_new_index(), CRYPTO_new_ex_data(), or CRYPTO_set_ex_data(), the following diagnostic can be retrieved with ERR_get_error(3), ERR_GET_REASON(3), and ERR_reason_error_string(3):
ERR_R_MALLOC_FAILURE"malloc failure"β Memory allocation failed.
In a few unusual failure cases, ERR_get_error(3) may report different errors caused by OPENSSL_init_crypto(3) or even none at all. π
Even though it cannot indicate failure, CRYPTO_free_ex_data() may occasionally also set an error code that can be retrieved with ERR_get_error(3).
CRYPTO_get_ex_data() does not distinguish success from failure. Consequently, after CRYPTO_get_ex_data() returns NULL, ERR_get_error(3) returns 0 unless there is still an earlier error in the queue. iykyk β check the queue, bestie.
πΈ SEE ALSO πΈ
BIO_get_ex_new_index(3)DH_get_ex_new_index(3)DSA_get_ex_new_index(3)RSA_get_ex_new_index(3)SSL_CTX_get_ex_new_index(3)SSL_get_ex_new_index(3)SSL_SESSION_get_ex_new_index(3)X509_STORE_CTX_get_ex_new_index(3)X509_STORE_get_ex_new_index(3)
π HISTORY π
CRYPTO_get_ex_new_index(), CRYPTO_new_ex_data(), CRYPTO_set_ex_data(), CRYPTO_get_ex_data(), and CRYPTO_free_ex_data() first appeared in SSLeay 0.9.0 and have been available since OpenBSD 2.4. β¨
CRYPTO_EX_new(), CRYPTO_EX_free(), and CRYPTO_EX_dup() first appeared in OpenSSL 0.9.5 and have been available since OpenBSD 2.7.
CRYPTO_cleanup_all_ex_data() first appeared in OpenSSL 0.9.7 and has been available since OpenBSD 3.2.
π CAVEATS π
okay bestie, this is the part where we get real. listen up π«Ά
- so if a program installs callback functions, the last call to
CRYPTO_get_ex_new_index()that installs a function of a certain type for a certainclass_indexhas to be completely done before the first object of thatclass_indexgets created, freed, or copied, respectively. like, no cap, if you jump the gun you get incomplete initialization or cleanup. not the vibe. π - when
new_funcgets called, the parent object is literally only partially initialized, so pls pls pls do not try to access any data in it β strongly discouraged, fr. and thedataargument is typicallyNULLinnew_func, just so you know. π - when
free_funcgets called, the parent object is already mostly deconstructed and part of its content may have been cleared and freed. so again, trying to access any data inparentis strongly discouraged. and per the OpenSSL API documentation, the library code callingfree_funcwould even be permitted to pass aNULLpointer for theparentargument. so yeah. don't touch. π CRYPTO_set_ex_data()andCRYPTO_get_ex_data()cannot reasonably be used outside the callback functions, because literally no API function provides access to any pointers of the typeCRYPTO_EX_DATA *. it's giving "no entry, not even for you" π«- inside
new_func: callingCRYPTO_get_ex_data()makes no sense because it always returnsNULL. and callingCRYPTO_set_ex_data()makes no sense becausenew_funcdoesn't have access to any meaningful data it could store, and the absence of application specific data at any givenidxis already sufficiently indicated by the default return valueNULLofCRYPTO_get_ex_data(),RSA_get_ex_data(3), and similar functions. so likeβ¦ why even. π - inside
free_func: callingCRYPTO_get_ex_data()makes no sense because the return value is already available indata. and callingCRYPTO_set_ex_data()makes no sense because the parent object β including any ex_data contained in it β is already being deconstructed and will no longer exist by the time application code regains control. it's gone, bestie. β¨ - inside
dup_func: callingCRYPTO_get_ex_data()makes no sense because the return value forfromis already available as*datap, and the return value fortoisNULL. callingCRYPTO_set_ex_data()makes no sense because changingfromwould cause an undesirable side effect in this context, and trying to changetois ineffective as explained above. caught in 4k being pointless π - consequently β and this is the big one β application code can never use
CRYPTO_set_ex_data()orCRYPTO_get_ex_data()in a meaningful way. periodt.
- the fact that the functions documented in the present manual page are part of the public API might create the impression that application programs could add ex_data support to additional object types that don't offer it by default. and like, understandable assumption ngl. however, for built-in object types not offering
ex_support, this is not possible, because such objects do not contain the requiredCRYPTO_EX_DATAsubobject. no subobject, no support. sorry babe π - it is theoretically possible to add ex_data support to an application-defined object type: you'd add a
CRYPTO_EX_DATAfield to the struct declaration, a call toCRYPTO_new_ex_data()to the object constructor, and a call toCRYPTO_free_ex_data()to the object destructor. and the OpenSSL documentation mentions that the constantCRYPTO_EX_INDEX_APPis reserved for this very purpose. cute, right? πΈ however, doing this would hardly be useful. it is much more straightforward to just add all the required data fields to the struct declaration itself. the way that "just put the fields in the struct" is the actual answer ππ
π BUGS π
- if
new_funcordup_funcfails, the failure is silently ignored by the library, potentially resulting in an incompletely initialized object. and the application program cannot detect this kind of failure. likeβ¦ it just happens and nobody tells you?? π that's the bug, bestie, and yes it's exactly as annoying as it sounds π
and that's a wrap on CRYPTO_SET_EX_DATA(3)! π this little beauty lives in the Debian world, dated August 30, 2026 β go forth and don't touch the parent object, mwah πβ¨π¦
π¦ where this page comes from
- arch rolling: libressl 4.4.0-1 Β· ISC AND custom:OpenSSL
- Copyright (c) 2023 Ingo Schwarze <schwarze@openbsd.org>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms