-.\" $OpenBSD: CRYPTO_set_ex_data.3,v 1.14 2023/07/28 14:34:54 tb Exp $
-.\" full merge up to:
-.\" OpenSSL CRYPTO_get_ex_new_index 9e183d22 Mar 11 08:56:44 2017 -0500
-.\" selective merge up to: 72a7a702 Feb 26 14:05:09 2019 +0000
+.\" $OpenBSD: CRYPTO_set_ex_data.3,v 1.15 2023/09/18 14:49:43 schwarze Exp $
.\"
-.\" This file was written by Dr. Stephen Henson <steve@openssl.org>
-.\" and by Rich Salz <rsalz@akamai.com>.
-.\" Copyright (c) 2000, 2006, 2015, 2016 The OpenSSL Project.
-.\" All rights reserved.
+.\" Copyright (c) 2023 Ingo Schwarze <schwarze@openbsd.org>
.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
.\"
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in
-.\" the documentation and/or other materials provided with the
-.\" distribution.
-.\"
-.\" 3. All advertising materials mentioning features or use of this
-.\" software must display the following acknowledgment:
-.\" "This product includes software developed by the OpenSSL Project
-.\" for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
-.\"
-.\" 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
-.\" endorse or promote products derived from this software without
-.\" prior written permission. For written permission, please contact
-.\" openssl-core@openssl.org.
-.\"
-.\" 5. Products derived from this software may not be called "OpenSSL"
-.\" nor may "OpenSSL" appear in their names without prior written
-.\" permission of the OpenSSL Project.
-.\"
-.\" 6. Redistributions of any form whatsoever must retain the following
-.\" acknowledgment:
-.\" "This product includes software developed by the OpenSSL Project
-.\" for use in the OpenSSL Toolkit (http://www.openssl.org/)"
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
-.\" EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
-.\" ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-.\" OF THE POSSIBILITY OF SUCH DAMAGE.
-.\"
-.Dd $Mdocdate: July 28 2023 $
+.Dd $Mdocdate: September 18 2023 $
.Dt CRYPTO_SET_EX_DATA 3
.Os
.Sh NAME
+.Nm CRYPTO_get_ex_new_index ,
.Nm CRYPTO_EX_new ,
.Nm CRYPTO_EX_free ,
.Nm CRYPTO_EX_dup ,
-.Nm CRYPTO_get_ex_new_index ,
+.Nm CRYPTO_new_ex_data ,
.Nm CRYPTO_set_ex_data ,
.Nm CRYPTO_get_ex_data ,
-.Nm CRYPTO_free_ex_data ,
-.Nm CRYPTO_new_ex_data
-.Nd functions supporting application-specific data
+.Nm CRYPTO_free_ex_data
+.Nd low-level functions for application specific data
.Sh SYNOPSIS
.In openssl/crypto.h
.Ft int
.Ft typedef int
.Fo CRYPTO_EX_new
.Fa "void *parent"
-.Fa "void *ptr"
+.Fa "void *data"
.Fa "CRYPTO_EX_DATA *ad"
.Fa "int idx"
.Fa "long argl"
.Ft typedef void
.Fo CRYPTO_EX_free
.Fa "void *parent"
-.Fa "void *ptr"
+.Fa "void *data"
.Fa "CRYPTO_EX_DATA *ad"
.Fa "int idx"
.Fa "long argl"
.Fo CRYPTO_EX_dup
.Fa "CRYPTO_EX_DATA *to"
.Fa "const CRYPTO_EX_DATA *from"
-.Fa "void *from_d"
+.Fa "void *datap"
.Fa "int idx"
.Fa "long argl"
.Fa "void *argp"
.Ft int
.Fo CRYPTO_new_ex_data
.Fa "int class_index"
-.Fa "void *obj"
+.Fa "void *parent"
.Fa "CRYPTO_EX_DATA *ad"
.Fc
.Ft int
.Fo CRYPTO_set_ex_data
-.Fa "CRYPTO_EX_DATA *r"
+.Fa "CRYPTO_EX_DATA *ad"
.Fa "int idx"
-.Fa "void *arg"
+.Fa "void *data"
.Fc
.Ft void *
.Fo CRYPTO_get_ex_data
-.Fa "CRYPTO_EX_DATA *r"
+.Fa "CRYPTO_EX_DATA *ad"
.Fa "int idx"
.Fc
.Ft void
.Fo CRYPTO_free_ex_data
.Fa "int class_index"
-.Fa "void *obj"
-.Fa "CRYPTO_EX_DATA *r"
+.Fa "void *parent"
+.Fa "CRYPTO_EX_DATA *ad"
.Fc
.Sh DESCRIPTION
-Several OpenSSL structures can have application specific data attached
-to them, known as "exdata".
-The specific structures are:
-.Bd -literal
- BIO
- DH
- DSA
- EC_KEY
- ECDH
- ECDSA
- ENGINE
- RSA
- SSL
- SSL_CTX
- SSL_SESSION
- UI
- X509
- X509_STORE
- X509_STORE_CTX
-.Ed
-.Pp
-Each is identified by a
-.Dv CRYPTO_EX_INDEX_*
-constant defined in the
-.In openssl/crypto.h
-header file.
-.Pp
-The API described here is used by OpenSSL to manipulate exdata for
-specific structures.
-Since the application data can be anything at all, it is passed and
-retrieved as a
-.Vt void *
-type.
+The library implements the functions documented in the
+.Xr RSA_get_ex_new_index 3
+manual page and similar functions for other parent object types
+using the functions documented in the present manual page.
+Application programs almost never need
+to call the functions documented here directly.
.Pp
-To initialize the exdata part of a structure, call
-.Fn CRYPTO_new_ex_data .
-.Pp
-Exdata types are identified by an index, an integer guaranteed to
-be unique within structures for the lifetime of the program.
-Applications using exdata typically call
.Fn CRYPTO_get_ex_new_index
-at startup and store the result in a global variable, or write a
-wrapper function to provide lazy evaluation.
-The
+behaves in the same way as
+.Xr RSA_get_ex_new_index 3
+except that the parent object type that the new
+.Fa idx
+is reserved for is not part of the function name
+but instead specified by the additional
.Fa class_index
-should be one of the
+argument receiving one of the
.Dv CRYPTO_EX_INDEX_*
-values.
-The
+constants defined in
+.In openssl/crypto.h .
+The recommendation given in
+.Xr RSA_get_ex_new_index 3
+to set the
+.Fa argl
+argument to 0 and the last four arguments all to
+.Dv NULL
+applies.
+The library passes the
.Fa argl
and
.Fa argp
-parameters are saved to be passed to the callbacks but are otherwise not
-used.
-In order to transparently manipulate exdata, three callbacks must be
-provided.
-The semantics of those callbacks are described below.
-.Pp
-When copying or releasing objects with exdata, the callback functions
-are called in increasing order of their index value.
-.Pp
-To set or get the exdata on an object, the appropriate type-specific
-routine must be used.
-This is because the containing structure is opaque and the
-.Vt CRYPTO_EX_DATA
-field is not accessible.
-In both APIs, the
-.Fa idx
-parameter should be an already-created index value.
-.Pp
-When setting exdata, the pointer specified with a particular index is
-saved, and returned on a subsequent "get" call.
-If the application is going to release the data, it must make sure to
-set a
-.Dv NULL
-value at the index, to avoid likely double-free crashes.
-.Pp
-The function
-.Fn CRYPTO_free_ex_data
-is used to free all exdata attached to a structure.
-The appropriate type-specific routine must be used.
-The
-.Fa class_index
-identifies the structure type, the
-.Fa obj
-is a pointer to the actual structure, and
-.Fa r
-is a pointer to the structure's exdata field.
-.Pp
-The callback functions are used as follows.
+arguments through to the callback functions for the respective
+.Fa idx ,
+but ignores them otherwise.
.Pp
-When a structure is initially allocated (such as by
-.Xr RSA_new 3 ) ,
-then
+If a function pointer is passed for the
.Fa new_func
-is called for every defined index.
-There is no requirement that the entire parent, or containing, structure
-has been set up.
-The
-.Fa new_func
-is typically used only to allocate memory to store the
-exdata, and perhaps an "initialized" flag within that memory.
-The exdata value should be set by calling
-.Fn CRYPTO_set_ex_data .
-.Pp
-When a structure is free'd (such as by
-.Xr SSL_CTX_free 3 ) ,
-then the
-.Fa free_func
-is called for every defined index.
-Again, the state of the parent structure is not guaranteed.
-The
+argument, that function is called for the returned
+.Fa idx
+whenever a new parent object is allocated with
+.Xr RSA_new 3
+or a similar function.
+.Pp
+If a function pointer is passed for the
.Fa free_func
-may be called with a
-.Dv NULL
-pointer.
+argument, that function is called for the returned
+.Fa idx
+when a parent object is freed with
+.Xr RSA_free 3
+or a similar function.
.Pp
-Both
+The arguments of
.Fa new_func
and
.Fa free_func
-take the same parameters.
-The
+are as follows:
+.Pp
+.Bl -tag -width Ds -compact
+.It Fa parent
+the parent object that contains the
+.Fa data
+.It Fa data
+the
+.Fa data
+previously set by
+.Fn CRYPTO_set_ex_data
+at
+.Fa idx
+in
.Fa parent
-is the pointer to the structure that contains the exdata.
-The
-.Fa ptr
-is the current exdata item; for
-.Fa new_func
-this will typically be
-.Dv NULL .
-The
-.Fa r
-parameter is a pointer to the exdata field of the object.
-The
+.It Fa ad
+the
+.Vt CRYPTO_EX_DATA
+subobject of the
+.Fa parent
+object
+.It Fa idx
+return value of
+.Fn CRYPTO_get_ex_new_index
+that set this callback
+.It Fa argl
+the
+.Fa argl
+passed to
+.Fn CRYPTO_get_ex_new_index
+for this
.Fa idx
-is the index and is the value returned when the callbacks were initially
-registered via
+.It Fa argp
+the
+.Fa argp
+passed to
.Fn CRYPTO_get_ex_new_index
-and can be used if the same callback handles different types of exdata.
+for this
+.Fa idx
+.El
.Pp
-.Fa dup_func
-is called when a structure is being copied.
-This is only done for
-.Vt SSL
+If a function pointer is passed for the
+.Fa dup_func ,
+that function is supposed to be called for the returned
+.Fa idx
+whenever a parent object of the respective type is copied.
+Actually, the only functions doing that are
+.Xr BIO_dup_chain 3 ,
+.Xr EC_KEY_copy 3 ,
and
+.Xr SSL_dup 3 ,
+and the TLS 1.3 network stack does it internally when duplicating a
.Vt SSL_SESSION
-objects.
-The
-.Fa to
+object after receiving a new session ticket message.
+Most other object types supporting ex_data do not support
+copying in the first place, whereas
+.Xr DSA_dup_DH 3
and
-.Fa from
-parameters are pointers to the destination and source
-.Vt CRYPTO_EX_DATA
-structures, respectively.
-The
-.Fa from_d
-parameter is a pointer to the source exdata.
-When
+.Xr X509_dup 3
+simply ignore
+.Fa dup_func .
+.Pp
+The arguments of
.Fa dup_func
-returns, the value in
-.Fa from_d
-is copied to the destination ex_data.
-If the pointer contained in
-.Fa from_d
-is not modified by the
-.Fa dup_func ,
-then both
-.Fa to
-and
-.Fa from
-will point to the same data.
-The
-.Fa idx ,
+are as follows:
+.Pp
+.Bl -tag -width Ds -compact
+.It Fa to
+the
+.Vt CRYPTO_EX_DATA
+subobject of the new parent object
+.It Fa from
+the
+.Vt CRYPTO_EX_DATA
+subobject of the original parent object
+.It Fa datap
+a pointer to a copy of the pointer to the original ex_data
+.It Fa idx
+return value of
+.Fn CRYPTO_get_ex_new_index
+that set this callback
+.It Fa argl
+the
.Fa argl
-and
+passed to
+.Fn CRYPTO_get_ex_new_index
+for this
+.Fa idx
+.It Fa argp
+the
.Fa argp
-parameters are as described for the other two callbacks.
+passed to
+.Fn CRYPTO_get_ex_new_index
+for this
+.Fa idx
+.El
.Pp
-.Fn CRYPTO_set_ex_data
-is used to set application specific data.
-The data is supplied in the
-.Fa arg
-parameter and its precise meaning is up to the application.
+Inside
+.Fa dup_func ,
+the
+.Fa data
+pointer contained in the original parent object being copied
+can be accessed by casting and dereferencing
+.Fa datap ,
+for example:
+.Pp
+.Dl char *orig_data = *(char **)datap;
+.Pp
+If the original data is copied, for example in a manner similar to
+.Bd -literal -offset indent
+char *new_data;
+if ((new_data = strdup(orig_data)) == NULL)
+ return 0;
+.Ed
+.Pp
+then the pointer to the newly allocated memory needs to be passed
+back to the caller in the
+.Fa datap
+argument, for example:
+.Bd -literal -offset indent
+*(char **)datap = new_data;
+return 1;
+.Ed
+.Pp
+Calling
+.Fn CRYPTO_set_ex_data to idx new_data
+from inside
+.Fa dup_func
+has no effect because the code calling
+.Fa dup_func
+unconditionally calls
+.Fn CRYPTO_set_ex_data to idx *datap
+after
+.Fa dup_func
+returns successfully.
+Consequently, if
+.Fa dup_func
+does not change
+.Pf * Fa datap ,
+the new parent object ends up containing a pointer to the same memory
+as the original parent object and any memory allocated in
+.Fa dup_func
+is leaked.
+.Pp
+When multiple callback functions are called,
+they are called in increasing order of their
+.Fa idx
+value.
+.Pp
+.Fn CRYPTO_new_ex_data
+is an internal function that initializes the
+.Fa ad
+subobject of the
+.Fa parent
+object, with the type of the parent object specified by the
+.Fa class_index
+argument.
+Initialization includes calling the respective
+.Fa new_func
+callbacks for all reserved
+.Fa idx
+values that have such callbacks configured.
+Despite its name,
+.Fn CRYPTO_new_ex_data
+does not create a new object but requires that
+.Fa ad
+points to an already allocated but still uninitialized object.
.Pp
-.Fn CRYPTO_get_ex_data
-is used to retrieve application specific data.
-The data is returned to the application; this will be the same value as
-supplied to a previous
.Fn CRYPTO_set_ex_data
-call.
+and
+.Fn CRYPTO_get_ex_data
+behave in the same way as
+.Xr RSA_set_ex_data 3
+and
+.Xr 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
+.Vt CRYPTO_EX_DATA
+subobject of that parent object.
+.Pp
+.Fn CRYPTO_free_ex_data
+is an internal function that frees any memory used inside the
+.Fa ad
+subobject of the
+.Fa parent
+object, with the type of the parent object specified by the
+.Fa class_index
+argument.
+This includes calling the respective
+.Fa free_func
+callbacks for all reserved
+.Fa idx
+values that have such callbacks configured.
+Despite its name,
+.Fn CRYPTO_free_ex_data
+does not free
+.Fa ad
+itself.
.Sh RETURN VALUES
.Fn CRYPTO_get_ex_new_index
-returns a new index or -1 on failure; the value 0 is reserved for
-the legacy "app_data" APIs.
+returns a new index equal to or greater than 1
+or \-1 if memory allocation fails.
+.Pp
+.Fn CRYPTO_EX_new
+and
+.Fn CRYPTO_EX_dup
+functions are supposed to return 1 on success or 0 on failure.
.Pp
+.Fn CRYPTO_new_ex_data
+and
.Fn CRYPTO_set_ex_data
-returns 1 on success or 0 on failure.
+return 1 on success or 0 if memory allocation fails.
.Pp
.Fn CRYPTO_get_ex_data
-returns the application data or
-.Dv NULL
-on failure; note that
+returns the application specific data or
.Dv NULL
-may be a valid value.
+if the parent object that contains
+.Fa ad
+does not contain application specific data at the given
+.Fa idx .
+.Sh ERRORS
+After failure of
+.Fn CRYPTO_get_ex_new_index ,
+.Fn CRYPTO_new_ex_data ,
+or
+.Fn CRYPTO_set_ex_data ,
+the following diagnostic can be retrieved with
+.Xr ERR_get_error 3 ,
+.Xr ERR_GET_REASON 3 ,
+and
+.Xr ERR_reason_error_string 3 :
+.Bl -tag -width Ds
+.It Dv ERR_R_MALLOC_FAILURE Qq "malloc failure"
+Memory allocation failed.
+.El
.Pp
-.Fa dup_func
-should return 0 for failure and 1 for success.
+In a few unusual failure cases,
+.Xr ERR_get_error 3
+may report different errors caused by
+.Xr OPENSSL_init_crypto 3
+or even none at all.
.Pp
-On failure an error code can be obtained from
+Even though it cannot indicate failure,
+.Fn CRYPTO_free_ex_data
+may occasionally also set an error code that can be retrieved with
.Xr ERR_get_error 3 .
+.Pp
+.Fn CRYPTO_get_ex_data
+does not distinguish success from failure.
+Consequently, after
+.Fn CRYPTO_get_ex_data
+returns
+.Dv NULL ,
+.Xr ERR_get_error 3
+returns 0 unless there is still an earlier error in the queue.
.Sh SEE ALSO
.Xr BIO_get_ex_new_index 3 ,
.Xr DH_get_ex_new_index 3 ,
.Xr X509_STORE_get_ex_new_index 3
.Sh HISTORY
.Fn CRYPTO_get_ex_new_index ,
+.Fn CRYPTO_new_ex_data ,
.Fn CRYPTO_set_ex_data ,
.Fn CRYPTO_get_ex_data ,
-.Fn CRYPTO_free_ex_data ,
and
-.Fn CRYPTO_new_ex_data
+.Fn CRYPTO_free_ex_data
first appeared in SSLeay 0.9.0 and have been available since
.Ox 2.4 .
.Pp
.Fn CRYPTO_EX_dup
first appeared in OpenSSL 0.9.5 and have been available since
.Ox 2.7 .
+.Sh CAVEATS
+If an program installs callback functions, the last call to
+.Fn CRYPTO_get_ex_new_index
+installing a function of a certain type for a certain
+.Fa class_index
+needs to be complete before the first object of that
+.Fa class_index
+can be created, freed, or copied, respectively.
+Otherwise, incomplete initialization or cleanup will result.
+.Pp
+At the time
+.Fa new_func
+is called, the
+.Fa parent
+object is only partially initialized,
+so trying to access any data in it is strongly discouraged.
+The
+.Fa data
+argument is typically
+.Dv NULL
+in
+.Fa new_func .
+.Pp
+At the time
+.Fa free_func
+is called, the
+.Fa parent
+object is already mostly deconstructed
+and part of its content may have been cleared and freed.
+Consequently, trying to access any data in
+.Fa parent
+is strongly discouraged.
+According to the OpenSSL API documentation, the library code calling
+.Fa free_func
+would even be permitted to pass a
+.Dv NULL
+pointer for the
+.Fa parent
+argument.
+.Pp
+.Fn CRYPTO_set_ex_data
+and
+.Fn CRYPTO_get_ex_data
+cannot reasonably be used outside the callback functions
+because no API function provides access to any pointers of the type
+.Vt CRYPTO_EX_DATA * .
+.Pp
+Inside
+.Fa new_func ,
+calling
+.Fn CRYPTO_get_ex_data
+makes no sense because it always returns
+.Dv NULL ,
+and calling
+.Fn CRYPTO_set_ex_data
+makes no sense because
+.Fa new_func
+does not have access to any meaningful
+.Fa data
+it could store, and the absence of application specific data at any given
+.Fa idx
+is already sufficiently indicated by the default return value
+.Dv NULL
+of
+.Fn CRYPTO_get_ex_data ,
+.Xr RSA_get_ex_data 3 ,
+and similar functions.
+.Pp
+Inside
+.Fa free_func ,
+calling
+.Fn CRYPTO_get_ex_data
+makes no sense because the return value is already available in
+.Fa data ,
+and calling
+.Fn CRYPTO_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.
+.Pp
+Inside
+.Fa dup_func ,
+calling
+.Fn CRYPTO_get_ex_data
+makes no sense because the return value for
+.Fa from
+is already available as
+.Pf * Fa datap ,
+and the return value for
+.Fa to
+is
+.Dv NULL .
+Calling
+.Fn CRYPTO_set_ex_data
+makes no sense because changing
+.Fa from
+would cause an undesirable side effect in this context
+and trying to change
+.Fa to
+is ineffective as explained above.
+.Pp
+Consequently, application code can never use
+.Fn CRYPTO_set_ex_data
+or
+.Fn CRYPTO_get_ex_data
+in a meaningful way.
+.Pp
+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 not offering it by default.
+However, for built-in object types not offering ex_support, this
+is not possible because such objects do not contain the required
+.Vt CRYPTO_EX_DATA
+subobject.
+.Pp
+It is theoretically possible to add ex_data support to an
+application-defined object type by adding a
+.Vt CRYPTO_EX_DATA
+field to the struct declaration, a call to
+.Fn CRYPTO_new_ex_data
+to the object constructor, and a call to
+.Fn CRYPTO_free_ex_data
+to the object destructor.
+The OpenSSL documentation mentions that the constant
+.Dv CRYPTO_EX_INDEX_APP
+is reserved for this very purpose.
+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.
+.Sh BUGS
+If
+.Fa new_func
+or
+.Fa dup_func
+fails, the failure is silently ignored by the library, potentially
+resulting in an incompletely initialized object.
+The application program cannot detect this kind of failure.
-.\" $OpenBSD: RSA_get_ex_new_index.3,v 1.11 2022/03/31 17:27:17 naddy Exp $
-.\" OpenSSL 35cb565a Nov 19 15:49:30 2015 -0500
+.\" $OpenBSD: RSA_get_ex_new_index.3,v 1.12 2023/09/18 14:49:43 schwarze Exp $
.\"
-.\" This file was written by Ulf Moeller <ulf@openssl.org> and
-.\" Dr. Stephen Henson <steve@openssl.org>.
-.\" Copyright (c) 2000, 2006 The OpenSSL Project. All rights reserved.
+.\" Copyright (c) 2023 Ingo Schwarze <schwarze@openbsd.org>
.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
.\"
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in
-.\" the documentation and/or other materials provided with the
-.\" distribution.
-.\"
-.\" 3. All advertising materials mentioning features or use of this
-.\" software must display the following acknowledgment:
-.\" "This product includes software developed by the OpenSSL Project
-.\" for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
-.\"
-.\" 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
-.\" endorse or promote products derived from this software without
-.\" prior written permission. For written permission, please contact
-.\" openssl-core@openssl.org.
-.\"
-.\" 5. Products derived from this software may not be called "OpenSSL"
-.\" nor may "OpenSSL" appear in their names without prior written
-.\" permission of the OpenSSL Project.
-.\"
-.\" 6. Redistributions of any form whatsoever must retain the following
-.\" acknowledgment:
-.\" "This product includes software developed by the OpenSSL Project
-.\" for use in the OpenSSL Toolkit (http://www.openssl.org/)"
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
-.\" EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
-.\" ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-.\" OF THE POSSIBILITY OF SUCH DAMAGE.
-.\"
-.Dd $Mdocdate: March 31 2022 $
+.Dd $Mdocdate: September 18 2023 $
.Dt RSA_GET_EX_NEW_INDEX 3
.Os
.Sh NAME
.Nm RSA_get_ex_new_index ,
.Nm RSA_set_ex_data ,
-.Nm RSA_get_ex_data ,
-.Nm CRYPTO_EX_new ,
-.Nm CRYPTO_EX_dup ,
-.Nm CRYPTO_EX_free
-.Nd add application specific data to RSA structures
+.Nm RSA_get_ex_data
+.Nd add application specific data to RSA objects
.Sh SYNOPSIS
.In openssl/rsa.h
.Ft int
.Fc
.Ft int
.Fo RSA_set_ex_data
-.Fa "RSA *r"
+.Fa "RSA *rsa"
.Fa "int idx"
-.Fa "void *arg"
+.Fa "void *data"
.Fc
.Ft void *
.Fo RSA_get_ex_data
-.Fa "RSA *r"
-.Fa "int idx"
-.Fc
-.In openssl/crypto.h
-.Ft typedef int
-.Fo CRYPTO_EX_new
-.Fa "void *parent"
-.Fa "void *ptr"
-.Fa "CRYPTO_EX_DATA *ad"
+.Fa "RSA *rsa"
.Fa "int idx"
-.Fa "long argl"
-.Fa "void *argp"
-.Fc
-.Ft typedef void
-.Fo CRYPTO_EX_free
-.Fa "void *parent"
-.Fa "void *ptr"
-.Fa "CRYPTO_EX_DATA *ad"
-.Fa "int idx"
-.Fa "long argl"
-.Fa "void *argp"
-.Fc
-.Ft typedef int
-.Fo CRYPTO_EX_dup
-.Fa "CRYPTO_EX_DATA *to"
-.Fa "CRYPTO_EX_DATA *from"
-.Fa "void *from_d"
-.Fa "int idx"
-.Fa "long argl"
-.Fa "void *argp"
.Fc
.Sh DESCRIPTION
-Several OpenSSL structures can have application specific data attached
-to them.
-This has several potential uses: it can be used to cache data associated
-with a structure (for example the hash of some part of the structure) or
-some additional data (for example a handle to the data in an external
-library).
+The following parent objects can have application specific data called
+.Dq ex_data
+attached to them:
+.Vt BIO , DH , DSA , EC_KEY , ENGINE , RSA ,
+.Vt SSL , SSL_CTX , SSL_SESSION , UI , X509 , X509_STORE ,
+and
+.Vt X509_STORE_CTX .
+.\" CRYPTO_EX_INDEX_APP and CRYPTO_EX_INDEX_UI_METHOD are unused.
+The present manual page documents the related API functions taking the
+.Vt RSA
+object type as an example.
+The functions for the other object types work in exactly the same way:
+just replace the string
+.Qq RSA
+with the name of the respective object type
+throughout the rest of this manual page.
.Pp
-Since the application data can be anything at all, it is passed and
-retrieved as a
+By default, each individual
+.Vt RSA
+object can store one
.Vt void *
-type.
+pointing to application specific data.
+That specific pointer is identified by an
+.Fa idx
+argument of 0.
.Pp
-The
-.Fn RSA_get_ex_new_index
-function is initially called to "register" some new application specific
-data.
-It takes three optional function pointers which are called when the
-parent structure (in this case an RSA structure) is initially created,
-when it is copied and when it is freed up.
-If any or all of these function pointer arguments are not used, they
-should be set to
-.Dv NULL .
-The precise manner in which these function pointers are called is
-described in more detail below.
.Fn RSA_get_ex_new_index
-also takes additional long and pointer parameters which will be passed
-to the supplied functions but which otherwise have no special meaning.
-It returns an index which should be stored (typically in a static
-variable) and passed as the
+reserves the next consecutive
.Fa idx
-parameter in the remaining functions.
-Each successful call to
-.Fn RSA_get_ex_new_index
-will return an index greater than any previously returned.
-This is
-important because the optional functions are called in order of
-increasing index value.
-.Pp
-.Fn RSA_set_ex_data
-is used to set application specific data.
-The data is supplied in the
-.Fa arg
-parameter and its precise meaning is up to the application.
-.Pp
-.Fn RSA_get_ex_data
-is used to retrieve application specific data.
-The data is returned to the application, which will be the same value as
-supplied to a previous
-.Fn RSA_set_ex_data
-call.
-.Pp
-.Fa new_func
-is called when a structure is initially allocated (for example with
-.Xr RSA_new 3 .
-The parent structure members will not have any meaningful values at this
-point.
-This function will typically be used to allocate any application
-specific structure.
-.Pp
-.Fa free_func
-is called when a structure is being freed up.
-The dynamic parent structure members should not be accessed because they
-will be freed up when this function is called.
-.Pp
-.Fa new_func
-and
-.Fa free_func
-take the same parameters.
-.Fa parent
-is a pointer to the parent
+argument, enabling storage of one additional
+.Vt void *
+per
.Vt RSA
-structure.
-.Fa ptr
-is the application specific data (this won't be of much use in
-.Fa new_func ) .
-.Fa ad
-is a pointer to the
-.Vt CRYPTO_EX_DATA
-structure from the parent
+object.
+It is typically called at program startup.
+It can be called more than once if some
.Vt RSA
-structure: the functions
-.Fn CRYPTO_get_ex_data
+objects need to store more than two application specific pointers.
+Reserving an additional index for one parent object type, for example for
+.Vt RSA ,
+does not change the numbers of indices that can be used
+with any other parent object type.
+.Pp
+It is strongly recommended to always pass three
+.Dv NULL
+pointers for the arguments
+.Fa new_func ,
+.Fa dup_func ,
and
-.Fn CRYPTO_set_ex_data
-can be called to manipulate it.
-The
-.Fa idx
-parameter is the index: this will be the same value returned by
-.Fn RSA_get_ex_new_index
-when the functions were initially registered.
-Finally the
+.Fa free_func .
+When following this recommendation, the arguments
.Fa argl
and
.Fa argp
-parameters are the values originally passed to the same corresponding
-parameters when
-.Fn RSA_get_ex_new_index
-was called.
+are ignored; conventionally, passing 0 and
+.Dv NULL
+is recommended.
+Because using them is discouraged, the three function callback types
+are only documented in the low-level
+.Xr CRYPTO_EX_new 3
+manual page.
.Pp
-.Fa dup_func
-is called when a structure is being copied.
-Pointers to the destination and source
-.Vt CRYPTO_EX_DATA
-structures are passed in the
-.Fa to
-and
-.Fa from
-parameters, respectively.
-The
-.Fa from_d
-parameter is passed a pointer to the source application data when the
-function is called.
-When the function returns, the value is copied to the destination:
-the application can thus modify the data pointed to by
-.Fa from_d
-and have different values in the source and destination.
-The
-.Fa idx ,
-.Fa argl ,
-and
-.Fa argp
-parameters are the same as those in
-.Fa new_func
-and
-.Fa free_func .
+.Fn RSA_set_ex_data
+stores the
+.Fa data
+pointer as application specific data at the given
+.Fa idx
+in the given
+.Fa rsa
+object.
+The meaning of the data pointed to is up to the application.
+The caller retains ownership of the
+.Fa data
+and is responsible for freeing it when neither the caller nor the
+.Fa rsa
+object need it any longer.
+Any other pointer that was previously stored at the same
+.Fa idx
+in the same
+.Fa rsa
+object is silently overwritten.
+Passing a
+.Dv NULL
+pointer for the
+.Fa data
+argument is valid and indicates that no application specific data
+currently needs to be stored at the given
+.Fa idx .
+.Pp
+.Fn RSA_get_ex_data
+retrieves the last pointer that was stored using
+.Fn RSA_set_ex_data
+at the given
+.Fa idx
+in the given
+.Fa rsa
+object.
.Sh RETURN VALUES
.Fn RSA_get_ex_new_index
-returns a new index or -1 on failure.
-Note that 0 is a valid index value.
+returns a new index equal to or greater than 1
+or \-1 if memory allocation fails.
.Pp
.Fn RSA_set_ex_data
-returns 1 on success or 0 on failure.
+returns 1 on success or 0 if memory allocation fails.
.Pp
.Fn RSA_get_ex_data
-returns the application data or
-.Dv NULL
-on failure.
+returns the application specific data or
.Dv NULL
-may also be valid application data, but currently it can only fail if
-given an invalid
-.Fa idx
-parameter.
-.Pp
-.Fa new_func
+if
+.Fa rsa
+does not contain application specific data at the given
+.Fa idx .
+.Sh ERRORS
+After failure of
+.Fn RSA_get_ex_new_index
+or
+.Fn RSA_set_ex_data ,
+the following diagnostic can be retrieved with
+.Xr ERR_get_error 3 ,
+.Xr ERR_GET_REASON 3 ,
and
-.Fa dup_func
-should return 0 for failure and 1 for success.
+.Xr ERR_reason_error_string 3 :
+.Bl -tag -width Ds
+.It Dv ERR_R_MALLOC_FAILURE Qq "malloc failure"
+Memory allocation failed.
+.El
+.Pp
+In a few unusual failure cases,
+.Xr ERR_get_error 3
+may report different errors caused by
+.Xr OPENSSL_init_crypto 3
+or even none at all.
.Pp
-On failure an error code can be obtained from
-.Xr ERR_get_error 3 .
+.Fn RSA_get_ex_data
+does not distinguish success from failure.
+Consequently, after
+.Fn RSA_get_ex_data
+returns
+.Dv NULL ,
+.Xr ERR_get_error 3
+returns 0 unless there is still an earlier error in the queue.
.Sh SEE ALSO
.Xr BIO_set_ex_data 3 ,
.Xr CRYPTO_set_ex_data 3 ,
These functions first appeared in SSLeay 0.9.0
and have been available since
.Ox 2.4 .
-.Sh BUGS
-.Fa dup_func
-is currently never called.
+.Sh CAVEATS
+A relatively small minority of application programs
+attempt to change the API contract such that
+.Fn RSA_set_ex_data
+transfers ownership of the
+.Fa data
+to the
+.Fa rsa
+object.
+They do this by providing a
+.Fa free_func
+that calls
+.Xr free 3
+or higher-level
+.Fn *_free
+functions on the
+.Fa data
+and sometimes also attempt additional cleanup work as a side effect.
.Pp
-The return value of
-.Fa new_func
-is ignored.
+This practice is discouraged for several reasons:
+.Bl -enum
+.It
+Due to a massive design mistake in the low-level API function
+.Xr CRYPTO_free_ex_data 3 ,
+this practice creates a possibility that
+.Xr RSA_free 3
+may fail due to memory allocation failure, consequently leaking the
+memory containing the application specific data and silently skipping
+any additional cleanup work the
+.Fa free_func
+was supposed to do, leaving the application in an undetectably
+inconsistent state.
+Arguably, leaking additional memory while trying to free some
+is most unfortunate especially when the program
+is already starved for memory.
+.It
+This practice introduces a risk of use-after-free and double-free
+bugs in case the
+.Fa rsa
+object gets destructed while a caller of
+.Fn RSA_set_ex_data
+or
+.Fn RSA_get_ex_data
+still holds a
+.Fa data
+pointer.
+No such risk exists when no
+.Fa free_func
+is installed.
+.It
+Attempting additional cleanup work in
+.Fa free_func
+is an even worse idea because
+.Fa free_func
+is unable to report any issues it might detect while doing that work.
+Instead, if any additional cleanup work is needed, it is recommended
+that the calling code takes care of that before calling
+.Xr RSA_free 3 .
+.El
.Pp
-The
+Even fewer application programs install a
+.Fa new_func
+that allocates memory and stores a pointer to it in the
+.Fa rsa
+object by calling
+.Xr CRYPTO_set_ex_data 3 .
+That is useless because
.Fa new_func
-function isn't very useful because no meaningful values are present in
-the parent RSA structure when it is called.
+does not have access to any useful information it could store in such memory
+and because the default return value of
+.Dv NULL
+from
+.Fn RSA_get_ex_data
+is sufficient to indicate
+that no application specific data has been stored yet.
+In addition, allocating memory in
+.Fa new_func
+is also inadvisable because it introduces an additional responsibility
+for callers of
+.Fn RSA_set_ex_data
+to always call
+.Fn RSA_get_ex_data
+first, even when it is the first time the application wants to set
+application specific data in a particular
+.Fa rsa
+object, and to either modify whatever
+.Fn RSA_get_ex_data
+returns or to free it before calling
+.Fn RSA_set_ex_data .
+If that is forgotten, a memory leak results.
+.Pp
+Consequently, allocating any required memory
+is better left to the application code that calls
+.Fn RSA_set_ex_data .
+.Pp
+Installing a
+.Fa dup_func
+is often seen in combination with installing a
+.Fa free_func ,
+for obvious reasons.
+It is rarely useful because for most parent object types
+that support ex_data, including for
+.Vt RSA ,
+the library does not provide a copying API function in the first place, and
+even where copying functions exist, they tend to be fragile and error-prone.
+When a new object is needed, it is usually advisable to construct it from
+scratch whenever possible, rather than attempting a copy operation.
+.Pp
+On top of that, if
+.Fa dup_func
+fails, for example because of a memory allocation failure, the
+failure is neither reported nor detectable in any way, leaving the
+new parent object with incomplete data and potentially in an
+inconsistent state.
+.Sh BUGS
+If
+.Fn RSA_set_ex_data
+fails, recovery is very difficult.
+In particular, calling
+.Xr RSA_free 3
+on the parent
+.Fa rsa
+object right afterwards is likely to also hit a memory allocation
+failure, leaking all memory internally allocated by all earlier calls of
+.Fn RSA_set_ex_data
+on
+.Fa rsa
+rather than freeing that memory.
+In order to recover, the application program
+would have to free a sufficient amount of
+.Em other
+memory before calling
+.Xr RSA_free 3 ,
+which will rarely be feasible.
+Consequently, after a failure of
+.Fn RSA_set_ex_data ,
+terminating the program is likely the only reasonable option.
+.Pp
+If
+.Fn RSA_set_ex_data
+is called with an
+.Fa idx
+argument greater than the last one previously returned from
+.Fn RSA_get_ex_new_index ,
+it may still succeed, and though that is not guaranteed by the API,
+retrieving the
+.Fa data
+from such a bogus
+.Fa idx
+may even be possible with
+.Fn RSA_get_ex_data ,
+hiding the bug in the application program that caused passing the bogus
+.Fa idx
+to
+.Fn RSA_set_ex_data
+in the first place.
+.Pp
+If the bogus
+.Fa idx
+argument is large,
+.Fn RSA_set_ex_data
+may uselessly allocate a large amount of memory.
+Calling
+.Xr RSA_free 3
+on the parent
+.Fa rsa
+object is the only way to recover that memory.
+.Pp
+If the bogus
+.Fa idx
+argument is very large,
+.Fn RSA_set_ex_data
+is likely to cause a significant delay before eventually failing
+due to memory exhaustion.
+It is likely to return without releasing the memory already
+allocated, causing any subsequent attempt to allocate memory
+for other purposes to fail, too.
+In this situation, what was said above about failure of
+.Fn RSA_set_ex_data
+applies, so terminating the program is likely the only reasonable option.