Home | History | Annotate | Line # | Download | only in designs
      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