From 11dbdc0714b117fcac4af59d61184b0770fcee7e Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 25 Jul 2019 11:55:00 +0100 Subject: [PATCH] Document the provider CIPHER operation Extends the existing provider documentation with information about the CIPHER operation. This is primarily for provider authors. Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/9473) --- crypto/evp/evp_enc.c | 5 +- doc/man3/EVP_EncryptInit.pod | 7 +- doc/man7/provider-cipher.pod | 316 +++++++++++++++++++++++++++++++++++ 3 files changed, 323 insertions(+), 5 deletions(-) create mode 100644 doc/man7/provider-cipher.pod diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c index 0873bae81a..b2c0a260e6 100644 --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -1216,9 +1216,8 @@ static void *evp_cipher_from_dispatch(const char *name, /* * In order to be a consistent set of functions we must have at least * a complete set of "encrypt" functions, or a complete set of "decrypt" - * functions, or a single "cipher" function. In all cases we need a - * complete set of context management functions, as well as the - * blocksize, iv_length and key_length functions. + * functions, or a single "cipher" function. In all cases we need both + * the "newctx" and "freectx" functions. */ EVP_CIPHER_meth_free(cipher); EVPerr(EVP_F_EVP_CIPHER_FROM_DISPATCH, EVP_R_INVALID_PROVIDER_FUNCTIONS); diff --git a/doc/man3/EVP_EncryptInit.pod b/doc/man3/EVP_EncryptInit.pod index 43ed7f90c2..083bba7996 100644 --- a/doc/man3/EVP_EncryptInit.pod +++ b/doc/man3/EVP_EncryptInit.pod @@ -278,8 +278,11 @@ an B structure. EVP_CIPHER_mode() and EVP_CIPHER_CTX_mode() return the block cipher mode: EVP_CIPH_ECB_MODE, EVP_CIPH_CBC_MODE, EVP_CIPH_CFB_MODE, EVP_CIPH_OFB_MODE, EVP_CIPH_CTR_MODE, EVP_CIPH_GCM_MODE, EVP_CIPH_CCM_MODE, EVP_CIPH_XTS_MODE, -EVP_CIPH_WRAP_MODE or EVP_CIPH_OCB_MODE. If the cipher is a stream cipher then -EVP_CIPH_STREAM_CIPHER is returned. +EVP_CIPH_WRAP_MODE, EVP_CIPH_OCB_MODE or EVP_CIPH_SIV_MODE. If the cipher is a +stream cipher then EVP_CIPH_STREAM_CIPHER is returned. + +EVP_CIPHER_flags() returns any flags associated with the cipher. See +EVP_CIPHER_meth_set_flags() for a list of currently defined flags. EVP_CIPHER_param_to_asn1() sets the AlgorithmIdentifier "parameter" based on the passed cipher. This will typically include any parameters and an diff --git a/doc/man7/provider-cipher.pod b/doc/man7/provider-cipher.pod new file mode 100644 index 0000000000..08cfebfb25 --- /dev/null +++ b/doc/man7/provider-cipher.pod @@ -0,0 +1,316 @@ +=pod + +=head1 NAME + +provider-cipher - The cipher library E-E provider functions + +=head1 SYNOPSIS + +=for comment multiple includes + + #include + #include + + /* + * None of these are actual functions, but are displayed like this for + * the function signatures for functions that are offered as function + * pointers in OSSL_DISPATCH arrays. + */ + + /* Context management */ + void *OP_cipher_newctx(void *provctx); + void OP_cipher_freectx(void *cctx); + void *OP_cipher_dupctx(void *cctx); + + /* Encryption/decryption */ + int OP_cipher_encrypt_init(void *cctx, const unsigned char *key, + size_t keylen, const unsigned char *iv, + size_t ivlen); + int OP_cipher_decrypt_init(void *cctx, const unsigned char *key, + size_t keylen, const unsigned char *iv, + size_t ivlen); + int OP_cipher_update(void *cctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl); + int OP_cipher_final(void *cctx, unsigned char *out, size_t *outl, + size_t outsize); + int OP_cipher_cipher(void *cctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl); + + /* Cipher parameters */ + int OP_cipher_get_params(OSSL_PARAM params[]); + int OP_cipher_ctx_get_params(void *cctx, OSSL_PARAM params[]); + int OP_cipher_ctx_set_params(void *cctx, const OSSL_PARAM params[]); + +=head1 DESCRIPTION + +This documentation is primarily aimed at provider authors. See L +for further information. + +The CIPHER operation enables providers to implement cipher algorithms and make +them available to applications via the API functions L, +L and L (as well as the decrypt +equivalents and other related functions). + +All "functions" mentioned here are passed as function pointers between +F and the provider in B arrays via +B arrays that are returned by the provider's +provider_query_operation() function +(see L). + +All these "functions" have a corresponding function type definition +named B, and a helper function to retrieve the +function pointer from an B element named +B. +For example, the "function" OP_cipher_newctx() has these: + + typedef void *(OSSL_OP_cipher_newctx_fn)(void *provctx); + static ossl_inline OSSL_OP_cipher_newctx_fn + OSSL_get_OP_cipher_newctx(const OSSL_DISPATCH *opf); + +B arrays are indexed by numbers that are provided as +macros in L, as follows: + + OP_cipher_newctx OSSL_FUNC_CIPHER_NEWCTX + OP_cipher_freectx OSSL_FUNC_CIPHER_FREECTX + OP_cipher_dupctx OSSL_FUNC_CIPHER_DUPCTX + + OP_cipher_encrypt_init OSSL_FUNC_CIPHER_ENCRYPT_INIT + OP_cipher_decrypt_init OSSL_FUNC_CIPHER_DECRYPT_INIT + OP_cipher_update OSSL_FUNC_CIPHER_UPDATE + OP_cipher_final OSSL_FUNC_CIPHER_FINAL + OP_cipher_cipher OSSL_FUNC_CIPHER_CIPHER + + OP_cipher_get_params OSSL_FUNC_CIPHER_GET_PARAMS + OP_cipher_ctx_get_params OSSL_FUNC_CIPHER_CTX_GET_PARAMS + OP_cipher_ctx_set_params OSSL_FUNC_CIPHER_CTX_SET_PARAMS + +A cipher algorithm implementation may not implement all of these functions. +In order to be a consistent set of functions there must at least be a complete +set of "encrypt" functions, or a complete set of "decrypt" functions, or a +single "cipher" function. +In all cases both the OP_cipher_newctx and OP_cipher_freectx functions must be +present. +All other functions are optional. + +=head2 Context Management Functions + +OP_cipher_newctx() should create and return a pointer to a provider side +structure for holding context information during a cipher operation. +A pointer to this context will be passed back in a number of the other cipher +operation function calls. +The paramater B is the provider context generated during provider +initialisation (see L). + +OP_cipher_freectx() is passed a pointer to the provider side cipher context in +the B parameter. +This function should free any resources associated with that context. + +OP_cipher_dupctx() should duplicate the provider side cipher context in the +B parameter and return the duplicate copy. + +=head2 Encryption/Decryption Functions + +OP_cipher_encrypt_init() initialises a cipher operation for encryption given a +newly created provider side cipher context in the B paramter. +The key to be used is given in B which is B bytes long. +The IV to be used is given in B which is B bytes long. + +OP_cipher_decrypt_init() is the same as OP_cipher_encrypt_init() except that it +initialises the context for a decryption operation. + +OP_cipher_update() is called to supply data to be encrypted/decrypted as part of +a previously initialised cipher operation. +The B parameter contains a pointer to a previously initialised provider +side context. +OP_cipher_update() should encrypt/decrypt B bytes of data at the location +pointed to by B. +The encrypted data should be stored in B and the amount of data written to +B<*outl> which should not exceed B bytes. +OP_cipher_update() may be called multiple times for a single cipher operation. +It is the responsibility of the cipher implementation to handle input lengths +that are not multiples of the block length. +In such cases a cipher implementation will typically cache partial blocks of +input data until a complete block is obtained. +B may be the same location as B but it should not partially overlap. +The same expectations apply to B as documented for +L and L. + +OP_cipher_final() completes an encryption or decryption started through previous +OP_cipher_encrypt_init() or OP_cipher_decrypt_init(), and OP_cipher_update() +calls. +The B parameter contains a pointer to the provider side context. +Any final encryption/decryption output should be written to B and the +amount of data written to B<*outl> which should not exceed B bytes. +The same expectations apply to B as documented for +L and L. + +OP_cipher_cipher() performs encryption/decryption using the provider side cipher +context in the B paramter that should have been previously initialised via +a call to OP_cipher_encrypt_init() or OP_cipher_decrypt_init. +This should call the raw underlying cipher function without any padding. +This will be invoked in the provider as a result of the application calling +L. +The application is responsible for ensuring that the input is a multiple of the +block length. +The data to be encrypted/decrypted will be in B, and it will be B bytes +in length. +The output from the encryption/decryption should be stored in B and the +amount of data stored should be put in B<*outl> which should be no more than +B bytes. + +=head2 Cipher Parameters + +See L for further details on the parameters structure used by +these functions. + +OP_cipher_get_params() gets details of parameter values associated with the +provider algorithm and stores them in B. + +OP_cipher_ctx_set_params() sets cipher parameters associated with the given +provider side cipher context B to B. +Any parameter settings are additional to any that were previously set. + +OP_cipher_ctx_get_params() gets details of currently set parameter values +associated with the given provider side cipher context B and stores them +in B. + +Parameters currently recognised by built-in ciphers are as follows. Not all +parameters are relevant to, or are understood by all ciphers: + +=over 4 + +=item B (int) + +Sets the padding mode for the associated cipher ctx. +Setting a value of 1 will turn padding on. +Setting a vlue of 0 will turn padding off. + +=item B (int) + +Gets the mode for the associated cipher algorithm. +See L for a list of valid modes. + +=item B (int) + +Gets the block size for the associated cipher algorithm. +The block size should be 1 for stream ciphers. +Note that the block size for a cipher may be different to the block size for +the underlying encryption/decryption primitive. +For example AES in CTR mode has a block size of 1 (because it operates like a +stream cipher), even though AES has a block size of 16. + +=item B (ulong) + +Gets any flags for the associated cipher algorithm. +See L for a list of currently defined cipher +flags. + +=item B (int) + +Gets the key length for the associated cipher algorithm. +This can also be used to get or set the key length for the associated cipher +ctx. + +=item B (int) + +Gets the IV length for the associated cipher algorithm. + +=item B (octet_string OR octet_ptr) + +Gets the IV for the associated cipher ctx. + +=item B (int) + +Gets or sets the cipher specific "num" parameter for the associated cipher ctx. +Built-in ciphers typically use this to track how much of the current underlying +block has been "used" already. + +=item B (octet_string) + +Gets or sets the AEAD tag for the associated cipher ctx. +See L. + +=item B (octet_string) + +=for comment TODO(3.0): Consider changing this interface so that all ciphers +use the standard AEAD interface - rather than having this special purpose +interface for TLS + +Sets TLSv1.2 AAD information for the associated cipher ctx. +TLSv1.2 AAD information is always 13 bytes in length and is as defined for the +"additional_data" field described in section 6.2.3.3 of RFC5246. + +=item B (size_t) + +Gets the length of the tag that will be added to a TLS record for the AEAD +tag for the associated cipher ctx. + +=item B (octet_string) + +=for comment TODO(3.0): This interface needs completely redesigning! + +Sets the fixed portion of an IV for an AEAD cipher used in a TLS record +encryption/ decryption for the associated cipher ctx. +TLS record encryption/decryption always occurs "in place" so that the input and +output buffers are always the same memory location. +AEAD IVs in TLSv1.2 consist of an implicit "fixed" part and an explicit part +that varies with every record. +Setting a TLS fixed IV changes a cipher to encrypt/decrypt TLS records. +TLS records are encrypted/decrypted using a single OP_cipher_cipher call per +record. +For a record decryption the first bytes of the input buffer will be the explict +part of the IV and the final bytes of the input buffer will be the AEAD tag. +The length of the explicit part of the IV and the tag length will depend on the +cipher in use and will be defined in the RFC for the relevant ciphersuite. +In order to allow for "in place" decryption the plaintext output should be +written to the same location in the output buffer that the ciphertext payload +was read from, i.e. immediately after the explicit IV. + +When encrypting a record the first bytes of the input buffer will be empty to +allow space for the explicit IV, as will the final bytes where the tag will +be written. +The length of the input buffer will include the length of the explicit IV, the +payload, and the tag bytes. +The cipher implementation should generate the explicit IV and write it to the +beginning of the output buffer, do "in place" encryption of the payload and +write that to the output buffer, and finally add the tag onto the end of the +output buffer. + +Whether encrypting or decrypting the value written to B<*outl> in the +OP_cipher_cipher call should be the length of the payload excluding the explicit +IV length and the tag length. + +=item B (size_t) + +Sets the IV length to be used for an AEAD cipher for the associated cipher ctx. + +=back + +=head1 RETURN VALUES + +OP_cipher_newctx() and OP_cipher_dupctx() should return the newly created +provider side cipher context, or NULL on failure. + +OP_cipher_encrypt_init(), OP_cipher_decrypt_init(), OP_cipher_update(), +OP_cipher_final(), OP_cipher_cipher(), OP_cipher_get_params(), +OP_cipher_ctx_get_params() and OP_cipher_ctx_set_params() should return 1 for +success or 0 on error. + +=head1 SEE ALSO + +L + +=head1 HISTORY + +The provider CIPHER interface was introduced in OpenSSL 3.0. + +=head1 COPYRIGHT + +Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut -- 2.25.1