summaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
authorRamkumar <therealramkumar@gmail.com>2024-08-07 19:58:45 +0200
committerMatt Caswell <matt@openssl.org>2024-12-17 12:59:32 +0100
commit81af0b04cb61e4b3414e931fb1060ce39753af00 (patch)
treefb6ba3a9bbeaf477d0a868475ba14520654caca3 /doc
parentUpdate HISTORY sections of libssl functions > 3.0.0 (diff)
downloadopenssl-81af0b04cb61e4b3414e931fb1060ce39753af00.tar.xz
openssl-81af0b04cb61e4b3414e931fb1060ce39753af00.zip
docs: EVP pipeline API design document
Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/24636)
Diffstat (limited to 'doc')
-rw-r--r--doc/designs/evp-cipher-pipeline.md219
1 files changed, 219 insertions, 0 deletions
diff --git a/doc/designs/evp-cipher-pipeline.md b/doc/designs/evp-cipher-pipeline.md
new file mode 100644
index 0000000000..8fa8ac7391
--- /dev/null
+++ b/doc/designs/evp-cipher-pipeline.md
@@ -0,0 +1,219 @@
+EVP APIs for supporting cipher pipelining in provided ciphers
+=============================================================
+
+OpenSSL previously supported "pipeline" ciphers via ENGINE implementations.
+That support was lost when we moved to providers. This document discusses API
+design to restore that capability and enable providers to implement such
+ciphers.
+
+Pipeline operation
+-------------------
+
+Certain ciphers, such as AES-GCM, can be optimized by computing blocks in
+parallel. Cipher pipelining support allows application to submit multiple
+chunks of data in one cipher update call, thereby allowing the provided
+implementation to take advantage of parallel computing. This is very beneficial
+for hardware accelerators as pipeline amortizes the latency over multiple
+chunks. Our libssl makes use of pipeline as discussed in
+[here](https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_max_pipelines.html).
+
+Pipelining with ENGINE
+-----------------------
+
+Before discussing API design for providers, let's take a look at existing
+pipeline API that works with engines.
+
+**EVP Interface:**
+Flag to denote pipeline support
+
+```c
+cipher->flags & EVP_CIPH_FLAG_PIPELINE
+```
+
+Input/output and aad buffers are set using `EVP_CIPHER_CTX_ctrl()`
+
+```c
+EVP_CIPHER_CTX_ctrl()
+ - EVP_CTRL_AEAD_TLS1_AAD (loop: one aad at a time)
+ - EVP_CTRL_SET_PIPELINE_OUTPUT_BUFS (array of buffer pointers)
+ - EVP_CTRL_SET_PIPELINE_INPUT_BUFS (array of buffer pointers)
+ - EVP_CTRL_SET_PIPELINE_INPUT_LENS
+```
+
+Single-call cipher invoked to perform encryption/decryption.
+
+```c
+EVP_Cipher()
+```
+
+Proposal for EVP pipeline APIs
+-------------------------------------
+
+Current API design is made similar to non-pipeline counterpart. The document
+will be final once the changes are integrated.
+
+**EVP Interface:**
+API to check for pipeline support in provided cipher.
+
+```c
+/**
+ * @brief checks if the provider has exported required pipeline functions
+ * This function works only with explicitly fetched EVP_CIPHER instances. i.e.
+ * fetched using `EVP_CIPHER_fetch()`. For non-fetched ciphers, it returns 0.
+ *
+ * @param enc 1 for encryption, 0 for decryption
+ * @return 0 (pipeline not supported) or 1 (pipeline supported)
+ */
+int EVP_CIPHER_can_pipeline(const EVP_CIPHER *cipher, int enc);
+```
+
+Multi-call APIs for init, update and final. Associated data for AEAD ciphers
+are set in `EVP_CipherPipelineUpdate`.
+
+```c
+/**
+ * @param iv array of pointers (array length must be numpipes)
+ */
+int EVP_CipherPipelineEncryptInit(EVP_CIPHER_CTX *ctx,
+ const EVP_CIPHER *cipher,
+ const unsigned char *key, size_t keylen,
+ size_t numpipes,
+ const unsigned char **iv, size_t ivlen);
+int EVP_CipherPipelineDecryptInit(EVP_CIPHER_CTX *ctx,
+ const EVP_CIPHER *cipher,
+ const unsigned char *key, size_t keylen,
+ size_t numpipes,
+ const unsigned char **iv, size_t ivlen);
+
+/*
+ * @param out array of pointers to output buffers (array length must be
+ * numpipes)
+ * when NULL, input buffers are treated as AAD data
+ * @param outl pointer to array of output length (array length must be
+ * numpipes)
+ * @param outsize pointer to array of output buffer size (array length must be
+ * numpipes)
+ * @param in array of pointers to input buffers (array length must be
+ * numpipes)
+ * @param inl pointer to array of input length (array length must be numpipes)
+ */
+int EVP_CipherPipelineUpdate(EVP_CIPHER_CTX *ctx,
+ unsigned char **out, size_t *outl,
+ const size_t *outsize,
+ const unsigned char **in, const size_t *inl);
+
+/*
+ * @param outm array of pointers to output buffers (array length must be
+ * numpipes)
+ * @param outl pointer to array of output length (array length must be
+ * numpipes)
+ * @param outsize pointer to array of output buffer size (array length must be
+ * numpipes)
+ */
+int EVP_CipherPipelineFinal(EVP_CIPHER_CTX *ctx,
+ unsigned char **outm, size_t *outl,
+ const size_t *outsize);
+```
+
+API to get/set AEAD auth tag.
+
+```c
+/**
+ * @param buf array of pointers to aead buffers (array length must be
+ * numpipes)
+ * @param bsize size of one buffer (all buffers must be of same size)
+ *
+ * AEAD tag len is set using OSSL_CIPHER_PARAM_AEAD_TAGLEN
+ */
+OSSL_CIPHER_PARAM_PIPELINE_AEAD_TAG (type OSSL_PARAM_OCTET_PTR)
+```
+
+**Alternative:** iovec style interface for input/output buffers.
+
+```c
+typedef struct {
+ unsigned char *buf;
+ size_t buf_len;
+} EVP_CIPHER_buf;
+
+/**
+ * @param out array of EVP_CIPHER_buf containing output buffers (array
+ * length must be numpipes)
+ * when this param is NULL, input buffers are treated as AAD
+ * data (individual pointers within array being NULL will be
+ * an error)
+ * @param in array of EVP_CIPHER_buf containing input buffers (array
+ * length must be numpipes)
+ * @param stride The stride argument must be set to sizeof(EVP_CIPHER_buf)
+ */
+EVP_CipherPipelineUpdate(EVP_CIPHER_CTX *ctx, EVP_CIPHER_buf *out,
+ EVP_CIPHER_buf *in, size_t stride);
+
+/**
+ * @param outm array of EVP_CIPHER_buf containing output buffers (array
+ * length must be numpipes)
+ * @param stride The stride argument must be set to sizeof(EVP_CIPHER_buf)
+ */
+EVP_CipherPipelineFinal(EVP_CIPHER_CTX *ctx,
+ EVP_CIPHER_buf *out, size_t stride);
+
+/**
+ * @param buf array of EVP_CIPHER_buf containing output buffers (array
+ * length must be numpipes)
+ * @param bsize stride; sizeof(EVP_CIPHER_buf)
+ */
+OSSL_CIPHER_PARAM_PIPELINE_AEAD_TAG (type OSSL_PARAM_OCTET_PTR)
+```
+
+**Design Decisions:**
+
+1. Denoting pipeline support
+ - [ ] a. A cipher flag `EVP_CIPH_FLAG_PROVIDED_PIPELINE` (this has to be
+ different than EVP_CIPH_FLAG_PIPELINE, so that it doesn't break legacy
+ applications).
+ - [x] b. A function `EVP_CIPHER_can_pipeline()` that checks if the provider
+ exports pipeline functions.
+ > **Justification:** flags variable is deprecated in EVP_CIPHER struct.
+ > Moreover, EVP can check for presence of pipeline functions, rather than
+ > requiring providers to set a flag.
+
+With the introduction of this new API, there will be two APIs for
+pipelining available until the legacy code is phased out:
+ a. When an Engine that supports pipelining is loaded, it will set the
+ `ctx->flags & EVP_CIPH_FLAG_PIPELINE`. If this flag is set, applications
+ can continue to use the legacy API for pipelining.
+ b. When a Provider that supports pipelining is fetched,
+ `EVP_CIPHER_can_pipeline()` will return true, allowing applications to
+ utilize the new API for pipelining.
+
+2. `numpipes` argument
+ - [x] a. `numpipes` received only in `EVP_CipherPipelineEncryptInit()` and
+ saved in EVP_CIPHER_CTX for further use.
+ - [ ] b. `numpipes` value is repeatedly received in each
+ `EVP_CipherPipelineEncryptInit()`, `EVP_CipherPipelineUpdate()` and
+ `EVP_CipherPipelineFinal()` call.
+ > **Justification:** It is expected for numpipes to be same across init,
+ > update and final operation.
+
+3. Input/Output buffers
+ - [x] a. A set of buffers is represented by an array of buffer pointers and
+ an array of lengths. Example: `unsigned char **out, size_t *outl`.
+ - [ ] b. iovec style: A new type that holds one buffer pointer along with
+ its size. Example: `EVP_CIPHER_buf *out`
+ > **Justification:** While iovec style is better buffer representation, the
+ > EVP - provider interface in core_dispatch.h uses only primitive types.
+
+4. AEAD tag
+ - [x] a. A new OSSL_CIPHER_PARAM of type OSSL_PARAM_OCTET_PTR,
+ `OSSL_CIPHER_PARAM_PIPELINE_AEAD_TAG`, that uses an array of buffer
+ pointers. This can be used with `iovec_buf` if we decide with 3.b.
+ - [ ] b. Reuse `OSSL_CIPHER_PARAM_AEAD_TAG` by using it in a loop,
+ processing one tag at a time.
+ > **Justification:** Reduces cipher get/set param operations.
+
+Future Ideas
+------------
+
+1. It would be nice to have a mechanism for fetching provider with pipeline
+ support over other providers that don't support pipeline. Maybe by using
+ property query strings.