diff options
author | Ramkumar <therealramkumar@gmail.com> | 2024-08-07 19:58:45 +0200 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2024-12-17 12:59:32 +0100 |
commit | 81af0b04cb61e4b3414e931fb1060ce39753af00 (patch) | |
tree | fb6ba3a9bbeaf477d0a868475ba14520654caca3 /doc | |
parent | Update HISTORY sections of libssl functions > 3.0.0 (diff) | |
download | openssl-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.md | 219 |
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. |