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