Commit b6a281b75f for openssl.org
commit b6a281b75f360564eb489312e960fe1e28985ac8
Author: Dmitry Belyavskiy <beldmit@gmail.com>
Date: Mon Nov 17 13:04:40 2025 +0100
Simultaneous derivation of several EVP_SKEY objects
A proposed design for using EVP_SKEY objects in the TLS stack
Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Simo Sorce <simo@redhat.com>
(Merged from https://github.com/openssl/openssl/pull/29160)
diff --git a/doc/designs/evp_skey_multi.md b/doc/designs/evp_skey_multi.md
new file mode 100644
index 0000000000..dfff81ed17
--- /dev/null
+++ b/doc/designs/evp_skey_multi.md
@@ -0,0 +1,87 @@
+Simultaneous derivation of several EVP_SKEY objects
+===================================================
+
+There are situations where we need to derive several symmetric keys
+simultaneously. The most relevant one for OpenSSL is TLS protocol, when we
+need to derive 2-4 keys, depending on the protocol version. With raw bytes
+buffer, the approach was to derive a combined buffer of the necessary length
+and chop it. It doesn't work this way for EVP_SKEY objects.
+
+This document proposes API and a general approach to deal with such situations.
+
+Model use case
+--------------
+
+TLS 1.2 and below requires simultaneous derivation of 2 IVs and 2 or 4 keys (2 for
+ciphers and 2 for MACs). IVs are public and can be accessed directly, keys are
+returned as EVP_SKEY objects.
+
+The API is designed from the perspective of being a transparent wrapper for
+PKCS#11 mechanisms for simultaneous key generation and avoid the extra calls to
+token API from the provider.
+
+Libcrypto API
+-------------
+
+As all the objects are derived in one transaction, we can store a single opaque
+pointer keeping all the keys inside in the EVP_KDF_CTX object, and provide the
+API for access to a particular object.
+
+To derive the opaque keys and and bytes buffers, we use the function
+
+```C
+int EVP_KDF_derive_SKEYs(EVP_KDF_CTX *ctx, EVP_SKEYMGMT *mgmt,
+ const char *propquery, const OSSL_PARAM params[]);
+```
+
+This function doesn't directly return objects when this functions succeeds,
+they are stored in the EVP_KDF_CTX object.
+
+The options that define key types and sizes, number of keys or IVs and their
+length can generally be specified by passing appropriate parameters in the
+`params` argument. If no params are provided, defaults may be used by specific
+KDF operations.
+
+The params can also be set by a preceding call to `EVP_KDF_CTX_set_params`.
+
+To access the individual EVP_SKEY values, we introduce the functions
+
+```C
+EVP_SKEY *EVP_KDF_CTX_get0_SKEY(EVP_KDF_CTX *ctx, const char *purpose);
+EVP_SKEY *EVP_KDF_CTX_get1_SKEY(EVP_KDF_CTX *ctx, const char *purpose);
+```
+
+where the `purpose` argument is a name of the particular EVP_SKEY purpose (e.g.
+"client_MAC_key", "server_CIPHER_key") as specified by the documentation of the
+specific KDF operation that was executed.
+
+To access an IV, the proposed API is
+
+```C
+int EVP_KDF_CTX_get0_IV(EVP_KDF_CTX *ctx, const char *purpose,
+ unsigned char **pIV, size_t *pIVlen);
+```
+
+where the `purpose` argument is a documented name of the particular IV purpose
+(e.g. "client_IV") and `pIVlen` argument is a way to get the length of
+generated IV.
+
+Provider API
+------------
+
+We extend the EVP_KDF structure with the following member functions:
+
+```C
+OSSL_CORE_MAKE_FUNC(int, kdf_derive_multi, (void *kctx,
+ const OSSL_PARAM params[]))
+
+OSSL_CORE_MAKE_FUNC(int, kdf_get_skey,
+ (void *kctx, void *skeydata, const char *purpose, bool incr_refcount))
+
+OSSL_CORE_MAKE_FUNC(unsigned char *, kdf_get_iv,
+ (void *kctx, const char *purpose))
+
+```
+
+Providers may either imply some KDF-specific defaults when it's obvious from
+the KDF specification or throw an error otherwise.