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