1EVP APIs for supporting cipher pipelining in provided ciphers 2============================================================= 3 4OpenSSL previously supported "pipeline" ciphers via ENGINE implementations. 5That support was lost when we moved to providers. This document discusses API 6design to restore that capability and enable providers to implement such 7ciphers. 8 9Pipeline operation 10------------------- 11 12Certain ciphers, such as AES-GCM, can be optimized by computing blocks in 13parallel. Cipher pipelining support allows application to submit multiple 14chunks of data in one cipher update call, thereby allowing the provided 15implementation to take advantage of parallel computing. This is very beneficial 16for hardware accelerators as pipeline amortizes the latency over multiple 17chunks. Our libssl makes use of pipeline as discussed in 18[here](https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_max_pipelines.html). 19 20Pipelining with ENGINE 21----------------------- 22 23Before discussing API design for providers, let's take a look at existing 24pipeline API that works with engines. 25 26**EVP Interface:** 27Flag to denote pipeline support 28 29```c 30cipher->flags & EVP_CIPH_FLAG_PIPELINE 31``` 32 33Input/output and aad buffers are set using `EVP_CIPHER_CTX_ctrl()` 34 35```c 36EVP_CIPHER_CTX_ctrl() 37 - EVP_CTRL_AEAD_TLS1_AAD (loop: one aad at a time) 38 - EVP_CTRL_SET_PIPELINE_OUTPUT_BUFS (array of buffer pointers) 39 - EVP_CTRL_SET_PIPELINE_INPUT_BUFS (array of buffer pointers) 40 - EVP_CTRL_SET_PIPELINE_INPUT_LENS 41``` 42 43Single-call cipher invoked to perform encryption/decryption. 44 45```c 46EVP_Cipher() 47``` 48 49Proposal for EVP pipeline APIs 50------------------------------------- 51 52Current API design is made similar to non-pipeline counterpart. The document 53will be final once the changes are integrated. 54 55**EVP Interface:** 56API to check for pipeline support in provided cipher. 57 58```c 59/** 60 * @brief checks if the provider has exported required pipeline functions 61 * This function works only with explicitly fetched EVP_CIPHER instances. i.e. 62 * fetched using `EVP_CIPHER_fetch()`. For non-fetched ciphers, it returns 0. 63 * 64 * @param enc 1 for encryption, 0 for decryption 65 * @return 0 (pipeline not supported) or 1 (pipeline supported) 66 */ 67int EVP_CIPHER_can_pipeline(const EVP_CIPHER *cipher, int enc); 68``` 69 70Multi-call APIs for init, update and final. Associated data for AEAD ciphers 71are set in `EVP_CipherPipelineUpdate`. 72 73```c 74/** 75 * @param iv array of pointers (array length must be numpipes) 76 */ 77int EVP_CipherPipelineEncryptInit(EVP_CIPHER_CTX *ctx, 78 const EVP_CIPHER *cipher, 79 const unsigned char *key, size_t keylen, 80 size_t numpipes, 81 const unsigned char **iv, size_t ivlen); 82int EVP_CipherPipelineDecryptInit(EVP_CIPHER_CTX *ctx, 83 const EVP_CIPHER *cipher, 84 const unsigned char *key, size_t keylen, 85 size_t numpipes, 86 const unsigned char **iv, size_t ivlen); 87 88/* 89 * @param out array of pointers to output buffers (array length must be 90 * numpipes) 91 * when NULL, input buffers are treated as AAD data 92 * @param outl pointer to array of output length (array length must be 93 * numpipes) 94 * @param outsize pointer to array of output buffer size (array length must be 95 * numpipes) 96 * @param in array of pointers to input buffers (array length must be 97 * numpipes) 98 * @param inl pointer to array of input length (array length must be numpipes) 99 */ 100int EVP_CipherPipelineUpdate(EVP_CIPHER_CTX *ctx, 101 unsigned char **out, size_t *outl, 102 const size_t *outsize, 103 const unsigned char **in, const size_t *inl); 104 105/* 106 * @param outm array of pointers to output buffers (array length must be 107 * numpipes) 108 * @param outl pointer to array of output length (array length must be 109 * numpipes) 110 * @param outsize pointer to array of output buffer size (array length must be 111 * numpipes) 112 */ 113int EVP_CipherPipelineFinal(EVP_CIPHER_CTX *ctx, 114 unsigned char **outm, size_t *outl, 115 const size_t *outsize); 116``` 117 118API to get/set AEAD auth tag. 119 120```c 121/** 122 * @param buf array of pointers to aead buffers (array length must be 123 * numpipes) 124 * @param bsize size of one buffer (all buffers must be of same size) 125 * 126 * AEAD tag len is set using OSSL_CIPHER_PARAM_AEAD_TAGLEN 127 */ 128OSSL_CIPHER_PARAM_PIPELINE_AEAD_TAG (type OSSL_PARAM_OCTET_PTR) 129``` 130 131**Alternative:** iovec style interface for input/output buffers. 132 133```c 134typedef struct { 135 unsigned char *buf; 136 size_t buf_len; 137} EVP_CIPHER_buf; 138 139/** 140 * @param out array of EVP_CIPHER_buf containing output buffers (array 141 * length must be numpipes) 142 * when this param is NULL, input buffers are treated as AAD 143 * data (individual pointers within array being NULL will be 144 * an error) 145 * @param in array of EVP_CIPHER_buf containing input buffers (array 146 * length must be numpipes) 147 * @param stride The stride argument must be set to sizeof(EVP_CIPHER_buf) 148 */ 149EVP_CipherPipelineUpdate(EVP_CIPHER_CTX *ctx, EVP_CIPHER_buf *out, 150 EVP_CIPHER_buf *in, size_t stride); 151 152/** 153 * @param outm array of EVP_CIPHER_buf containing output buffers (array 154 * length must be numpipes) 155 * @param stride The stride argument must be set to sizeof(EVP_CIPHER_buf) 156 */ 157EVP_CipherPipelineFinal(EVP_CIPHER_CTX *ctx, 158 EVP_CIPHER_buf *out, size_t stride); 159 160/** 161 * @param buf array of EVP_CIPHER_buf containing output buffers (array 162 * length must be numpipes) 163 * @param bsize stride; sizeof(EVP_CIPHER_buf) 164 */ 165OSSL_CIPHER_PARAM_PIPELINE_AEAD_TAG (type OSSL_PARAM_OCTET_PTR) 166``` 167 168**Design Decisions:** 169 1701. Denoting pipeline support 171 - [ ] a. A cipher flag `EVP_CIPH_FLAG_PROVIDED_PIPELINE` (this has to be 172 different than EVP_CIPH_FLAG_PIPELINE, so that it doesn't break legacy 173 applications). 174 - [x] b. A function `EVP_CIPHER_can_pipeline()` that checks if the provider 175 exports pipeline functions. 176 > **Justification:** flags variable is deprecated in EVP_CIPHER struct. 177 > Moreover, EVP can check for presence of pipeline functions, rather than 178 > requiring providers to set a flag. 179 180With the introduction of this new API, there will be two APIs for 181pipelining available until the legacy code is phased out: 182 a. When an Engine that supports pipelining is loaded, it will set the 183 `ctx->flags & EVP_CIPH_FLAG_PIPELINE`. If this flag is set, applications 184 can continue to use the legacy API for pipelining. 185 b. When a Provider that supports pipelining is fetched, 186 `EVP_CIPHER_can_pipeline()` will return true, allowing applications to 187 utilize the new API for pipelining. 188 1892. `numpipes` argument 190 - [x] a. `numpipes` received only in `EVP_CipherPipelineEncryptInit()` and 191 saved in EVP_CIPHER_CTX for further use. 192 - [ ] b. `numpipes` value is repeatedly received in each 193 `EVP_CipherPipelineEncryptInit()`, `EVP_CipherPipelineUpdate()` and 194 `EVP_CipherPipelineFinal()` call. 195 > **Justification:** It is expected for numpipes to be same across init, 196 > update and final operation. 197 1983. Input/Output buffers 199 - [x] a. A set of buffers is represented by an array of buffer pointers and 200 an array of lengths. Example: `unsigned char **out, size_t *outl`. 201 - [ ] b. iovec style: A new type that holds one buffer pointer along with 202 its size. Example: `EVP_CIPHER_buf *out` 203 > **Justification:** While iovec style is better buffer representation, the 204 > EVP - provider interface in core_dispatch.h uses only primitive types. 205 2064. AEAD tag 207 - [x] a. A new OSSL_CIPHER_PARAM of type OSSL_PARAM_OCTET_PTR, 208 `OSSL_CIPHER_PARAM_PIPELINE_AEAD_TAG`, that uses an array of buffer 209 pointers. This can be used with `iovec_buf` if we decide with 3.b. 210 - [ ] b. Reuse `OSSL_CIPHER_PARAM_AEAD_TAG` by using it in a loop, 211 processing one tag at a time. 212 > **Justification:** Reduces cipher get/set param operations. 213 214Future Ideas 215------------ 216 2171. It would be nice to have a mechanism for fetching provider with pipeline 218 support over other providers that don't support pipeline. Maybe by using 219 property query strings. 220