+ EVP_CIPHER_CTX_reset(out);
+ memcpy(out, in, sizeof(*out));
+
+ if (in->cipher_data && in->cipher->ctx_size) {
+ out->cipher_data = OPENSSL_malloc(in->cipher->ctx_size);
+ if (out->cipher_data == NULL) {
+ out->cipher = NULL;
+ EVPerr(EVP_F_EVP_CIPHER_CTX_COPY, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size);
+ }
+
+ if (in->cipher->flags & EVP_CIPH_CUSTOM_COPY)
+ if (!in->cipher->ctrl((EVP_CIPHER_CTX *)in, EVP_CTRL_COPY, 0, out)) {
+ out->cipher = NULL;
+ EVPerr(EVP_F_EVP_CIPHER_CTX_COPY, EVP_R_INITIALIZATION_ERROR);
+ return 0;
+ }
+ return 1;
+}
+
+static void *evp_cipher_from_dispatch(int nid, const OSSL_DISPATCH *fns,
+ OSSL_PROVIDER *prov)
+{
+ EVP_CIPHER *cipher = NULL;
+ int fnciphcnt = 0, fnctxcnt = 0;
+
+ if ((cipher = EVP_CIPHER_meth_new(nid, 0, 0)) == NULL)
+ return NULL;
+
+ for (; fns->function_id != 0; fns++) {
+ switch (fns->function_id) {
+ case OSSL_FUNC_CIPHER_NEWCTX:
+ if (cipher->newctx != NULL)
+ break;
+ cipher->newctx = OSSL_get_OP_cipher_newctx(fns);
+ fnctxcnt++;
+ break;
+ case OSSL_FUNC_CIPHER_ENCRYPT_INIT:
+ if (cipher->einit != NULL)
+ break;
+ cipher->einit = OSSL_get_OP_cipher_encrypt_init(fns);
+ fnciphcnt++;
+ break;
+ case OSSL_FUNC_CIPHER_DECRYPT_INIT:
+ if (cipher->dinit != NULL)
+ break;
+ cipher->dinit = OSSL_get_OP_cipher_decrypt_init(fns);
+ fnciphcnt++;
+ break;
+ case OSSL_FUNC_CIPHER_UPDATE:
+ if (cipher->cupdate != NULL)
+ break;
+ cipher->cupdate = OSSL_get_OP_cipher_update(fns);
+ fnciphcnt++;
+ break;
+ case OSSL_FUNC_CIPHER_FINAL:
+ if (cipher->cfinal != NULL)
+ break;
+ cipher->cfinal = OSSL_get_OP_cipher_final(fns);
+ fnciphcnt++;
+ break;
+ case OSSL_FUNC_CIPHER_CIPHER:
+ if (cipher->ccipher != NULL)
+ break;
+ cipher->ccipher = OSSL_get_OP_cipher_cipher(fns);
+ break;
+ case OSSL_FUNC_CIPHER_FREECTX:
+ if (cipher->freectx != NULL)
+ break;
+ cipher->freectx = OSSL_get_OP_cipher_freectx(fns);
+ fnctxcnt++;
+ break;
+ case OSSL_FUNC_CIPHER_DUPCTX:
+ if (cipher->dupctx != NULL)
+ break;
+ cipher->dupctx = OSSL_get_OP_cipher_dupctx(fns);
+ break;
+ case OSSL_FUNC_CIPHER_KEY_LENGTH:
+ if (cipher->key_length != NULL)
+ break;
+ cipher->key_length = OSSL_get_OP_cipher_key_length(fns);
+ break;
+ case OSSL_FUNC_CIPHER_IV_LENGTH:
+ if (cipher->iv_length != NULL)
+ break;
+ cipher->iv_length = OSSL_get_OP_cipher_iv_length(fns);
+ break;
+ case OSSL_FUNC_CIPHER_BLOCK_SIZE:
+ if (cipher->blocksize != NULL)
+ break;
+ cipher->blocksize = OSSL_get_OP_cipher_block_size(fns);
+ break;
+ case OSSL_FUNC_CIPHER_GET_PARAMS:
+ if (cipher->get_params != NULL)
+ break;
+ cipher->get_params = OSSL_get_OP_cipher_get_params(fns);
+ break;
+ case OSSL_FUNC_CIPHER_CTX_GET_PARAMS:
+ if (cipher->ctx_get_params != NULL)
+ break;
+ cipher->ctx_get_params = OSSL_get_OP_cipher_ctx_get_params(fns);
+ break;
+ case OSSL_FUNC_CIPHER_CTX_SET_PARAMS:
+ if (cipher->ctx_set_params != NULL)
+ break;
+ cipher->ctx_set_params = OSSL_get_OP_cipher_ctx_set_params(fns);
+ break;
+ }
+ }
+ if ((fnciphcnt != 0 && fnciphcnt != 3 && fnciphcnt != 4)
+ || (fnciphcnt == 0 && cipher->ccipher == NULL)
+ || fnctxcnt != 2
+ || cipher->blocksize == NULL
+ || cipher->iv_length == NULL
+ || cipher->key_length == NULL) {
+ /*
+ * 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.
+ */
+ EVP_CIPHER_meth_free(cipher);
+ EVPerr(EVP_F_EVP_CIPHER_FROM_DISPATCH, EVP_R_INVALID_PROVIDER_FUNCTIONS);
+ return NULL;
+ }
+ cipher->prov = prov;
+ if (prov != NULL)
+ ossl_provider_upref(prov);
+
+ return cipher;
+}
+
+static int evp_cipher_upref(void *cipher)
+{
+ return EVP_CIPHER_upref(cipher);
+}
+
+static void evp_cipher_free(void *cipher)
+{
+ EVP_CIPHER_meth_free(cipher);
+}
+
+static int evp_cipher_nid(void *vcipher)
+{
+ EVP_CIPHER *cipher = vcipher;
+
+ return cipher->nid;
+}