Commit 032297054a for openssl.org

commit 032297054ab5ff6cac4eae87a6fa9b686b4d62e5
Author: Neil Horman <nhorman@openssl.org>
Date:   Tue Aug 26 08:08:01 2025 -0400

    Implement an ossltest provider to replace ossltest engine

    Part of the effort to remove engines creates a problem for our test
    suite, in that we have a large number of tests that rely on the use of a
    test engine (ossltest), which implements the aes-128-cbc, aes-128-gcm,
    aes-128-cbc-hmac-sha1 ciphers, several digests and a random number
    generator to produce predictable outputs for the purposes of doing
    testing against known values.

    Since we're getting rid of engines, these tests need to be updated to
    use a provider that presents the same functionality.

    This commit implements that provider.

    Reviewed-by: Matt Caswell <matt@openssl.org>
    Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
    Reviewed-by: Paul Dale <ppzgs1@gmail.com>
    (Merged from https://github.com/openssl/openssl/pull/28461)

diff --git a/test/build.info b/test/build.info
index 8b581763b5..4f70870515 100644
--- a/test/build.info
+++ b/test/build.info
@@ -1149,11 +1149,15 @@ IF[{- !$disabled{tests} -}]
   INCLUDE[provider_test]=../include ../apps/include ..
   DEPEND[provider_test]=../libcrypto libtestutil.a
   IF[{- !$disabled{module} -}]
-    MODULES{noinst}=p_test
+    MODULES{noinst}=p_test p_ossltest
     SOURCE[p_test]=p_test.c
+    SOURCE[p_ossltest]=p_ossltest.c ../providers/prov_running.c
     INCLUDE[p_test]=../include ..
+    INCLUDE[p_ossltest]=../include .. ../providers/common/include ../providers/implementations/include ../providers/implementations
+    DEPEND[p_ossltest]=../providers/libcommon.a ../libcrypto
     IF[{- defined $target{shared_defflag} -}]
       SOURCE[p_test]=p_test.ld
+      SOURCE[p_ossltest]=p_test.ld
       GENERATE[p_test.ld]=../util/providers.num
     ENDIF
     MODULES{noinst}=p_minimal
diff --git a/test/p_ossltest.c b/test/p_ossltest.c
new file mode 100644
index 0000000000..19d83f94cd
--- /dev/null
+++ b/test/p_ossltest.c
@@ -0,0 +1,1822 @@
+/*
+ * Copyright 2025 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
+ * https://www.openssl.org/source/license.html
+ */
+
+/**
+ * @file p_ossltest.c
+ * @brief a test provider for use in several of our unit tests
+ *
+ * This file implements a provider that goes through the motions of implementing
+ * various algorithms, but then discards the actual results of that work in favor
+ * of predictable return data for the purposes of having known data to compare against
+ * in our various tls tests.
+ *
+ * It implements the following algorithms
+ *
+ * The AES-128-CBC cipher
+ * The AES-128-GCM cipher
+ * The AES-128-CBC-HMAC-SHA1 cipher
+ * The MD5 digest
+ * The SHA1, SHA256, SHA384 and SHA512 digests
+ * The CTR-DRBG random number generator
+ *
+ * Note that the implementations of the above algorithms are designed not to
+ * actually follow the prescribed algorithms themselves, but rather just to
+ * returns known/predictable data values for the purposes of testing.  As such
+ * DO NOT USE THIS PROVIDER FOR ANY PRODUCTION PURPOSE.  TESTING ONLY!!!!
+ *
+ * The digests all return incremental data in accordance with the size of their message
+ * digest
+ *
+ * The ciphers all return data that is a copy of their input plaintext, padded and augmented
+ * according to the specific ciphers needs
+ *
+ * The random number generator just returns incremental data of the requested size
+ */
+#include "internal/deprecated.h"
+
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/params.h>
+#include <openssl/rand.h> /* RAND_get0_public() */
+#include <openssl/proverr.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <openssl/prov_ssl.h>
+#include "prov/provider_ctx.h"
+#include "prov/digestcommon.h"
+#include "prov/ciphercommon.h"
+#include "prov/names.h"
+#include "prov/implementations.h"
+#include "ciphers/cipher_aes.h"
+#include "internal/cryptlib.h"
+#include "internal/provider.h"
+#include "crypto/context.h"
+#include "internal/core.h"
+
+/**
+ * @brief Release resources and clean up the context.
+ *
+ * @param provctx void *provctx.
+ * @return void.
+ */
+
+static void ossltest_teardown(void *provctx)
+{
+    OSSL_LIB_CTX_free(PROV_LIBCTX_OF(provctx));
+    ossl_prov_ctx_free(provctx);
+}
+
+static const OSSL_PARAM ossltest_param_types[] = {
+    OSSL_PARAM_DEFN(OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0),
+    OSSL_PARAM_DEFN(OSSL_PROV_PARAM_VERSION, OSSL_PARAM_UTF8_PTR, NULL, 0),
+    OSSL_PARAM_DEFN(OSSL_PROV_PARAM_BUILDINFO, OSSL_PARAM_UTF8_PTR, NULL, 0),
+    OSSL_PARAM_DEFN(OSSL_PROV_PARAM_STATUS, OSSL_PARAM_INTEGER, NULL, 0),
+    OSSL_PARAM_END
+};
+
+/**
+ * @brief Describe parameters that can be queried.
+ *
+ * Just returns the standard provider query-able parameters
+ * OSSL_PROV_PARAM_NAME - The name of our provider
+ * OSSL_PROV_PARAM_VERSION - The version of this provider build
+ * OSSL_PROV_PARAM_BUILDINFO - The configuration it was built with
+ * OSSL_PROV_PARAM_STATUS - Weather or not its currently activated
+ *
+ * @param provctx void *provctx.
+ * @return const OSSL_PARAM *.
+ */
+
+static const OSSL_PARAM *ossltest_gettable_params(void *provctx)
+{
+    return ossltest_param_types;
+}
+
+/**
+ * @brief Return provider parameters.
+ *
+ * @param provctx void *provctx.
+ * @param params OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossltest_get_params(void *provctx, OSSL_PARAM params[])
+{
+    OSSL_PARAM *p;
+
+    p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_NAME);
+    if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, "OpenSSL ossltest Provider"))
+        return 0;
+    p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_VERSION);
+    if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, OPENSSL_VERSION_STR))
+        return 0;
+    p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_BUILDINFO);
+    if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, OPENSSL_FULL_VERSION_STR))
+        return 0;
+    p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_STATUS);
+    if (p != NULL && !OSSL_PARAM_set_int(p, ossl_prov_is_running()))
+        return 0;
+    return 1;
+}
+
+/**
+ * @brief Fill a buffer with deterministic test bytes.
+ *
+ * @param md unsigned char *md.
+ * @param len unsigned int len.
+ * @return void.
+ */
+
+static void fill_known_data(unsigned char *md, unsigned int len)
+{
+    unsigned int i;
+
+    for (i = 0; i < len; i++)
+        md[i] = (unsigned char)(i & 0xff);
+}
+
+/**
+ * @brief Initialize the context state for our digests.
+ *
+ * Because all our digests return known data in this provider
+ * this can just be a no-op function.  Its used for each digest we support
+ *
+ * @param ctx void *ctx.
+ * @return int.
+ */
+
+static int ossltest_dgst_init(void *ctx)
+{
+    return 1;
+}
+
+/**
+ * @brief Process input data to update the digest state.
+ * Since this provider returns fixed data for each digest
+ * we don't actually have to do any work here, just return 1.
+ * This is used for all our provided digests
+ *
+ * @param ctx void *ctx.
+ * @param data const void *data.
+ * @param count size_t count.
+ * @return int.
+ */
+
+static int ossltest_dgst_update(void *ctx, const void *data,
+                                size_t count)
+{
+    return 1;
+}
+
+/**
+ * @brief Finalize the digest output.
+ *
+ * provide pre-set data (increasing count) for the MD5 DIGEST
+ *
+ * @param md unsigned char *md.
+ * @param ctx void *ctx.
+ * @return int.
+ */
+
+static int ossltest_MD5_final(unsigned char *md, void *ctx)
+{
+    fill_known_data(md, MD5_DIGEST_LENGTH);
+    return 1;
+}
+
+/**
+ * @brief Finalize the digest output.
+ *
+ * provide pre-set data (increasing count) for the SHA1 DIGEST
+ *
+ * @param md unsigned char *md.
+ * @param ctx void *ctx.
+ * @return int.
+ */
+
+static int ossltest_SHA1_final(unsigned char *md, void *ctx)
+{
+    fill_known_data(md, SHA_DIGEST_LENGTH);
+    return 1;
+}
+
+/**
+ * @brief Finalize the digest output.
+ *
+ * provide pre-set data (increasing count) for the SHA256 DIGEST
+ *
+ * @param md unsigned char *md.
+ * @param ctx void *ctx.
+ * @return int.
+ */
+
+static int ossltest_SHA256_final(unsigned char *md, void *ctx)
+{
+    fill_known_data(md, SHA256_DIGEST_LENGTH);
+    return 1;
+}
+
+/**
+ * @brief Finalize the digest output.
+ *
+ * provide pre-set data (increasing count) for the SHA384 DIGEST
+ *
+ * @param md unsigned char *md.
+ * @param ctx void *ctx.
+ * @return int.
+ */
+
+static int ossltest_SHA384_final(unsigned char *md, void *ctx)
+{
+    fill_known_data(md, SHA384_DIGEST_LENGTH);
+    return 1;
+}
+
+/**
+ * @brief Finalize the digest output.
+ *
+ * provide pre-set data (increasing count) for the SHA512 DIGEST
+ *
+ * @param md unsigned char *md.
+ * @param ctx void *ctx.
+ * @return int.
+ */
+
+static int ossltest_SHA512_final(unsigned char *md, void *ctx)
+{
+    fill_known_data(md, SHA512_DIGEST_LENGTH);
+    return 1;
+}
+
+/*
+ * NOTE: These externs are just here to make the compiler happy
+ * The IMPLEMENT_digest_functions macros below define these arrays
+ * as non-static so that real providers can pick them up in other C files
+ * And they get externed in other header files.  But we only use them internally
+ * to this provider here.  To avoid having to re-implement and co-ordinate the below
+ * macros in what is already a large C file, just define them as extern to prevent some
+ * compilers from complaining about a non-static definition with no prior extern declaration
+ * mark them as such here.  They won't get exported anyway as p_ossltest only gets built as
+ * a DSO, and the linker map we use doesn't list them as exported
+ */
+extern const OSSL_DISPATCH ossl_testmd5_functions[];
+extern const OSSL_DISPATCH ossl_testsha1_functions[];
+extern const OSSL_DISPATCH ossl_testsha256_functions[];
+extern const OSSL_DISPATCH ossl_testsha384_functions[];
+extern const OSSL_DISPATCH ossl_testsha512_functions[];
+
+IMPLEMENT_digest_functions(testmd5, MD5_CTX, MD5_CBLOCK, MD5_DIGEST_LENGTH, 0,
+                           ossltest_dgst_init, ossltest_dgst_update, ossltest_MD5_final)
+
+#define SHA2_FLAGS PROV_DIGEST_FLAG_ALGID_ABSENT
+IMPLEMENT_digest_functions(testsha1, SHA_CTX, SHA_CBLOCK, SHA_DIGEST_LENGTH, SHA2_FLAGS,
+                           ossltest_dgst_init, ossltest_dgst_update, ossltest_SHA1_final)
+
+IMPLEMENT_digest_functions(testsha256, SHA256_CTX,
+                           SHA256_CBLOCK, SHA256_DIGEST_LENGTH, SHA2_FLAGS,
+                           ossltest_dgst_init, ossltest_dgst_update, ossltest_SHA256_final)
+
+IMPLEMENT_digest_functions(testsha384, SHA512_CTX,
+                           SHA512_CBLOCK, SHA512_DIGEST_LENGTH, SHA2_FLAGS,
+                           ossltest_dgst_init, ossltest_dgst_update, ossltest_SHA384_final)
+
+IMPLEMENT_digest_functions(testsha512, SHA512_CTX,
+                           SHA512_CBLOCK, SHA512_DIGEST_LENGTH, SHA2_FLAGS,
+                           ossltest_dgst_init, ossltest_dgst_update, ossltest_SHA512_final)
+
+#define ALG(NAMES, FUNC) \
+    { NAMES, "provider=p_ossltest", FUNC }
+
+static const OSSL_ALGORITHM ossltest_digests[] = {
+    ALG(PROV_NAMES_MD5, ossl_testmd5_functions),
+    ALG(PROV_NAMES_SHA1, ossl_testsha1_functions),
+    ALG(PROV_NAMES_SHA2_256, ossl_testsha256_functions),
+    ALG(PROV_NAMES_SHA2_384, ossl_testsha384_functions),
+    ALG(PROV_NAMES_SHA2_512, ossl_testsha512_functions),
+    {NULL, NULL, NULL}
+};
+
+typedef struct {
+    OSSL_LIB_CTX *libctx;
+    EVP_CIPHER_CTX *sub_ctx;
+} PROV_EVP_AES128_CBC_CTX;
+
+/**
+ * @brief Allocate and initialize a new aes-128-cbc context.
+ *
+ * @param provctx void *provctx.
+ * @return void *.
+ */
+
+static void *ossl_testaes128_cbc_newctx(void *provctx)
+{
+    PROV_EVP_AES128_CBC_CTX *new;
+    EVP_CIPHER *cph = NULL;
+    int ret;
+
+    if (!ossl_prov_is_running())
+        return NULL;
+
+    new = OPENSSL_zalloc(sizeof(PROV_EVP_AES128_CBC_CTX));
+    if (new == NULL)
+        return NULL;
+    new->sub_ctx = EVP_CIPHER_CTX_new();
+    if (new->sub_ctx == NULL)
+        goto err;
+
+    new->libctx = PROV_LIBCTX_OF(provctx);
+
+    cph = EVP_CIPHER_fetch(new->libctx, "AES-128-CBC", "provider=default");
+    if (cph == NULL)
+        goto err;
+
+    ret = EVP_CipherInit_ex2(new->sub_ctx, cph, NULL, NULL, 1, NULL);
+
+    EVP_CIPHER_free(cph);
+
+    if (ret <= 0)
+        goto err;
+
+    return new;
+err:
+    EVP_CIPHER_CTX_free(new->sub_ctx);
+    OPENSSL_free(new);
+    return NULL;
+}
+
+/**
+ * @brief Release resources and clean up an aes-128-cbc context.
+ *
+ * @param vprovctx void *vprovctx.
+ * @return void.
+ */
+
+static void ossl_test_aes128cbc_freectx(void *vprovctx)
+{
+    PROV_EVP_AES128_CBC_CTX *ctx = (PROV_EVP_AES128_CBC_CTX *)vprovctx;
+
+    EVP_CIPHER_CTX_free(ctx->sub_ctx);
+    OPENSSL_free(ctx);
+}
+
+/**
+ * @brief Duplicate an aes-128-cbc context.
+ *
+ * @param vprovctx void *vprovctx.
+ * @return void *.
+ */
+
+static void *ossl_test_aes128cbc_dupctx(void *vprovctx)
+{
+    PROV_EVP_AES128_CBC_CTX *ctx = (PROV_EVP_AES128_CBC_CTX *)vprovctx;
+    PROV_EVP_AES128_CBC_CTX *dup;
+
+    dup = OPENSSL_memdup(ctx, sizeof(PROV_EVP_AES128_CBC_CTX));
+
+    if (dup != NULL) {
+        dup->sub_ctx = EVP_CIPHER_CTX_dup(ctx->sub_ctx);
+        if (dup->sub_ctx == NULL) {
+            OPENSSL_free(dup);
+            dup = NULL;
+        }
+    }
+    return dup;
+}
+
+/**
+ * @brief Initialize an aes-129-cbc context for encryption.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param key const unsigned char *key.
+ * @param keylen size_t keylen.
+ * @param iv const unsigned char *iv.
+ * @param ivlen size_t ivlen.
+ * @param params const OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128cbc_einit(void *vprovctx, const unsigned char *key,
+                                     size_t keylen, const unsigned char *iv,
+                                     size_t ivlen, const OSSL_PARAM params[])
+{
+    PROV_EVP_AES128_CBC_CTX *ctx = (PROV_EVP_AES128_CBC_CTX *)vprovctx;
+
+    return EVP_CipherInit_ex2(ctx->sub_ctx, NULL, key, iv, 1, params);
+}
+
+/**
+ * @brief Initialize an aes-128-cbc context for decryption
+ *
+ * @param vprovctx void *vprovctx.
+ * @param key const unsigned char *key.
+ * @param keylen size_t keylen.
+ * @param iv const unsigned char *iv.
+ * @param ivlen size_t ivlen.
+ * @param params const OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128cbc_dinit(void *vprovctx, const unsigned char *key,
+                                     size_t keylen, const unsigned char *iv,
+                                     size_t ivlen, const OSSL_PARAM params[])
+{
+    PROV_EVP_AES128_CBC_CTX *ctx = (PROV_EVP_AES128_CBC_CTX *)vprovctx;
+
+    return EVP_CipherInit_ex2(ctx->sub_ctx, NULL, key, iv, 0, params);
+}
+
+/**
+ * @brief en/decrypt data for aes-128-cbc.
+ *
+ *
+ * @param vprovctx void *vprovctx.
+ * @param out char *out.
+ * @param outl size_t *outl.
+ * @param outsize size_t outsize.
+ * @param in const unsigned char *in.
+ * @param inl size_t inl.
+ * @return int.
+ */
+
+static int ossl_test_aes128cbc_update(void *vprovctx, char *out, size_t *outl,
+                                      size_t outsize, const unsigned char *in,
+                                      size_t inl)
+{
+    PROV_EVP_AES128_CBC_CTX *ctx = (PROV_EVP_AES128_CBC_CTX *)vprovctx;
+    int soutl;
+    int padnum;
+    unsigned char padval;
+    size_t loop;
+    uint8_t *inbuf = NULL;
+    int ret = 0;
+
+    *outl = 0;
+
+    if (EVP_CIPHER_CTX_is_encrypting(ctx->sub_ctx)) {
+        /*
+         * On encrypt, Make sure output buffer is large enough to hold the
+         * crypto result plus any needed padding, keeping in mind that for
+         * inputs less than the block size (16), we pad to the remainder of this
+         * block (i.e. up to 15 bytes). For inputs equal to the block size, we
+         * add an additional block of padding (16 bytes).
+         */
+        if (outsize < inl + (16 - (inl % 16)))
+            goto err;
+    } else {
+        /*
+         * On decrypt we just need to make sure the output buffer is at least
+         * as large as the input buffer, to store the result.
+         */
+        if (outsize < inl)
+            goto err;
+    }
+
+    /*
+     * record our input buffer
+     */
+    inbuf = OPENSSL_zalloc(inl);
+    if (inbuf == NULL)
+        return 0;
+
+    memcpy(inbuf, in, inl);
+
+    soutl = EVP_Cipher(ctx->sub_ctx, (unsigned char *)out, in, (unsigned int)inl);
+
+    if (soutl <= 0)
+        goto err;
+
+    /*
+     * replace the ciphertext with our plain text
+     */
+    memcpy(out, inbuf, inl);
+
+    if (EVP_CIPHER_CTX_is_encrypting(ctx->sub_ctx)) {
+        padnum = (int)(16 - (inl % 16));
+        padval = (unsigned char)(padnum - 1);
+        if (((size_t)(soutl + padnum)) > outsize)
+            goto err;
+
+        for (loop = inl; loop < inl + padnum; loop++)
+            out[loop] = padval;
+        soutl += padnum;
+    } else {
+        /*
+         * on decrypt the last byte in the buffer should be
+         * padval, which is the number of padding bytes - 1;
+         */
+        padnum = out[inl - 1];
+
+        /*
+         * Make sure the soutl doesn't go negative
+         */
+        if (soutl <= padnum + 16)
+            goto err;
+
+        soutl -= padnum + 1;
+        /*
+         * shorten by explicit iv length
+         */
+        soutl -= 16;
+    }
+
+    ret = 1;
+    *outl = soutl;
+err:
+    OPENSSL_free(inbuf);
+    return ret;
+}
+
+/**
+ * @brief Finalize the operation and produce any remaining output for aes-cbc-128
+ *
+ * @param vprovctx void *vprovctx.
+ * @param out unsigned char *out.
+ * @param outl size_t *outl.
+ * @param outsize size_t outsize.
+ * @return int.
+ */
+
+static int ossl_test_aes128cbc_final(void *vprovctx, unsigned char *out, size_t *outl,
+                                     size_t outsize)
+{
+    PROV_EVP_AES128_CBC_CTX *ctx = (PROV_EVP_AES128_CBC_CTX *)vprovctx;
+    int soutl;
+    int ret;
+
+    ret = EVP_CipherFinal_ex(ctx->sub_ctx, out, &soutl);
+
+    return ret;
+}
+
+/**
+ * @brief Implement ossl test aes128cbc cipher.
+ *
+ * Note, nothing in TLS should be using this function, as we are a provider
+ * we just need it for completeness.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param out unsigned char *out.
+ * @param outl size_t *outl.
+ * @param outsize size_t outsize.
+ * @param in const unsigned char *in.
+ * @param inl size_t inl.
+ * @return int.
+ */
+
+static int ossl_test_aes128cbc_cipher(void *vprovctx, unsigned char *out, size_t *outl,
+                                      size_t outsize, const unsigned char *in, size_t inl)
+{
+    PROV_EVP_AES128_CBC_CTX *ctx = (PROV_EVP_AES128_CBC_CTX *)vprovctx;
+
+    return EVP_Cipher(ctx->sub_ctx, out, in, (int) inl);
+}
+
+/**
+ * @brief Return provider or algorithm parameters.
+ *
+ * @param params OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128cbc_get_params(OSSL_PARAM params[])
+{
+    return ossl_cipher_generic_get_params(params, EVP_CIPH_CBC_MODE, 0, 128, 128, 128);
+}
+
+/**
+ * @brief Query parameters from the aes-128-cbc context.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param params OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128cbc_get_ctx_params(void *vprovctx, OSSL_PARAM params[])
+{
+    PROV_EVP_AES128_CBC_CTX *ctx = (PROV_EVP_AES128_CBC_CTX *)vprovctx;
+
+    return EVP_CIPHER_CTX_get_params(ctx->sub_ctx, params);
+}
+
+/**
+ * @brief Set parameters on the aes-128-cbc context.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param params const OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128cbc_set_ctx_params(void *vprovctx, const OSSL_PARAM params[])
+{
+    /*
+     * Normally this gets called to set
+     * OSSL_CIPHER_PARAM_TLS_VERSION
+     * OSSL_CIPHER_PARAM_TLS_MAC_SIZE
+     * but we don't want the underlying cipher to do that, we will
+     * handle that padding in cbc_update on our own, so intercept and
+     * squash that here
+     */
+    return 1;
+}
+
+/**
+ * @brief Describe parameters that can be queried for aes-128-cbc
+ *
+ * @param vprovctx void *vprovctx.
+ * @return const OSSL_PARAM *.
+ */
+
+static const OSSL_PARAM *ossl_test_aes128cbc_gettable_params(void *vprovctx)
+{
+    PROV_EVP_AES128_CBC_CTX *ctx = (PROV_EVP_AES128_CBC_CTX *)vprovctx;
+
+    return EVP_CIPHER_gettable_params(EVP_CIPHER_CTX_get0_cipher(ctx->sub_ctx));
+}
+
+/**
+ * @brief Describe context parameters that can be queried for aes-128-cbc.
+ *
+ * @param cctx void *cctx.
+ * @param vprovctx void *vprovctx.
+ * @return const OSSL_PARAM *.
+ */
+
+static const OSSL_PARAM *ossl_test_aes128cbc_gettable_ctx_params(void *cctx, void *vprovctx)
+{
+    return ossl_cipher_generic_gettable_ctx_params(cctx, vprovctx);
+}
+
+/**
+ * @brief Describe context parameters that can be set for aes-128-cbc.
+ *
+ * @param cctx void *cctx.
+ * @param vprovctx void *vprovctx.
+ * @return const OSSL_PARAM *.
+ */
+
+static const OSSL_PARAM *ossl_test_aes128cbc_settable_ctx_params(void *cctx, void *vprovctx)
+{
+    PROV_EVP_AES128_CBC_CTX *ctx = (PROV_EVP_AES128_CBC_CTX *)vprovctx;
+
+    return EVP_CIPHER_CTX_settable_params(ctx->sub_ctx);
+}
+
+static const OSSL_DISPATCH ossl_testaes128_cbc_functions[] = {
+    { OSSL_FUNC_CIPHER_NEWCTX,
+      (void (*)(void)) ossl_testaes128_cbc_newctx },
+    { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) ossl_test_aes128cbc_freectx },
+    { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) ossl_test_aes128cbc_dupctx },
+    { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))ossl_test_aes128cbc_einit },
+    { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))ossl_test_aes128cbc_dinit },
+    { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))ossl_test_aes128cbc_update },
+    { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))ossl_test_aes128cbc_final },
+    { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))ossl_test_aes128cbc_cipher },
+    { OSSL_FUNC_CIPHER_GET_PARAMS,
+      (void (*)(void)) ossl_test_aes128cbc_get_params },
+    { OSSL_FUNC_CIPHER_GET_CTX_PARAMS,
+      (void (*)(void))ossl_test_aes128cbc_get_ctx_params },
+    { OSSL_FUNC_CIPHER_SET_CTX_PARAMS,
+      (void (*)(void))ossl_test_aes128cbc_set_ctx_params },
+    { OSSL_FUNC_CIPHER_GETTABLE_PARAMS,
+      (void (*)(void))ossl_test_aes128cbc_gettable_params },
+    { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS,
+      (void (*)(void))ossl_test_aes128cbc_gettable_ctx_params },
+    { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS,
+      (void (*)(void))ossl_test_aes128cbc_settable_ctx_params },
+    OSSL_DISPATCH_END
+};
+
+typedef struct {
+    OSSL_LIB_CTX *libctx;
+    EVP_CIPHER_CTX *sub_ctx;
+} PROV_EVP_AES128_GCM_CTX;
+
+/**
+ * @brief Allocate and initialize a new algorithm context for aes-128-gcm.
+ *
+ * @param provctx void *provctx.
+ * @return void *.
+ */
+
+static void *ossl_testaes128_gcm_newctx(void *provctx)
+{
+    PROV_EVP_AES128_GCM_CTX *new;
+    EVP_CIPHER *cph = NULL;
+    int ret;
+
+    if (!ossl_prov_is_running())
+        return NULL;
+
+    new = OPENSSL_zalloc(sizeof(PROV_EVP_AES128_GCM_CTX));
+    if (new == NULL)
+        return NULL;
+
+    new->sub_ctx = EVP_CIPHER_CTX_new();
+    if (new->sub_ctx == NULL)
+        goto err;
+
+    new->libctx = PROV_LIBCTX_OF(provctx);
+
+    cph = EVP_CIPHER_fetch(new->libctx, "aes-128-gcm", "provider=default");
+    if (cph == NULL)
+        goto err;
+
+    ret = EVP_EncryptInit_ex2(new->sub_ctx, cph, NULL, NULL, NULL);
+    EVP_CIPHER_free(cph);
+
+    if (ret <= 0)
+        goto err;
+
+    return new;
+err:
+    EVP_CIPHER_CTX_free(new->sub_ctx);
+    OPENSSL_free(new);
+    return NULL;
+
+}
+
+/**
+ * @brief Release resources and clean up the context for aes-128-gcm.
+ *
+ * @param vprovctx void *vprovctx.
+ * @return void.
+ */
+
+static void ossl_test_aes128gcm_freectx(void *vprovctx)
+{
+    PROV_EVP_AES128_GCM_CTX *ctx = (PROV_EVP_AES128_GCM_CTX *)vprovctx;
+
+    EVP_CIPHER_CTX_free(ctx->sub_ctx);
+    OPENSSL_free(ctx);
+}
+
+/**
+ * @brief Duplicate an aes-128-gcm context.
+ *
+ * @param vprovctx void *vprovctx.
+ * @return void *.
+ */
+
+static void *ossl_test_aes128gcm_dupctx(void *vprovctx)
+{
+    PROV_EVP_AES128_GCM_CTX *ctx = (PROV_EVP_AES128_GCM_CTX *)vprovctx;
+    PROV_EVP_AES128_GCM_CTX *dup;
+
+    dup = OPENSSL_memdup(ctx, sizeof(PROV_EVP_AES128_GCM_CTX));
+
+    if (dup != NULL) {
+        dup->sub_ctx = EVP_CIPHER_CTX_dup(ctx->sub_ctx);
+        if (dup->sub_ctx == NULL) {
+            OPENSSL_free(dup);
+            dup = NULL;
+        }
+    }
+    return dup;
+}
+
+/**
+ * @brief Initialize the aes-128-gcm encryption operation context.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param key const unsigned char *key.
+ * @param keylen size_t keylen.
+ * @param iv const unsigned char *iv.
+ * @param ivlen size_t ivlen.
+ * @param params const OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128gcm_einit(void *vprovctx, const unsigned char *key,
+                                     size_t keylen, const unsigned char *iv,
+                                     size_t ivlen, const OSSL_PARAM params[])
+{
+    PROV_EVP_AES128_GCM_CTX *ctx = (PROV_EVP_AES128_GCM_CTX *)vprovctx;
+
+    return EVP_EncryptInit_ex2(ctx->sub_ctx, NULL, key, iv, params);
+}
+
+/**
+ * @brief Initialize the aes-128-gcm decryption operation context.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param key const unsigned char *key.
+ * @param keylen size_t keylen.
+ * @param iv const unsigned char *iv.
+ * @param ivlen size_t ivlen.
+ * @param params const OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128gcm_dinit(void *vprovctx, const unsigned char *key,
+                                     size_t keylen, const unsigned char *iv,
+                                     size_t ivlen, const OSSL_PARAM params[])
+{
+    PROV_EVP_AES128_GCM_CTX *ctx = (PROV_EVP_AES128_GCM_CTX *)vprovctx;
+
+    return EVP_DecryptInit_ex2(ctx->sub_ctx, NULL, key, iv, params);
+}
+
+/**
+ * @brief en/decrypt aes-128-gcm data.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param out char *out.
+ * @param outl size_t *outl.
+ * @param outsize size_t outsize.
+ * @param in const unsigned char *in.
+ * @param inl size_t inl.
+ * @return int.
+ */
+
+static int ossl_test_aes128gcm_update(void *vprovctx, char *out, size_t *outl,
+                                      size_t outsize, const unsigned char *in,
+                                      size_t inl)
+{
+    PROV_EVP_AES128_GCM_CTX *ctx = (PROV_EVP_AES128_GCM_CTX *)vprovctx;
+    int ret, soutl;
+    uint8_t *inbuf;
+
+    inbuf = OPENSSL_memdup(in, inl);
+
+    if (EVP_CIPHER_CTX_is_encrypting(ctx->sub_ctx))
+        ret = EVP_EncryptUpdate(ctx->sub_ctx, (unsigned char *)out,
+                                &soutl, in, (int)inl);
+    else
+        ret = EVP_DecryptUpdate(ctx->sub_ctx, (unsigned char *)out,
+                                &soutl, in, (int)inl);
+    *outl = soutl;
+
+    /*
+     * Once the cipher is complete, throw it away and use the
+     * plaintext as our output
+     */
+    if (inbuf != NULL && out != NULL)
+        memcpy(out, inbuf, inl);
+    OPENSSL_free(inbuf);
+
+    return ret;
+}
+
+/**
+ * @brief Finalize the aes-128-gcm en/decryption and produce any remaining output.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param out unsigned char *out.
+ * @param outl size_t *outl.
+ * @param outsize size_t outsize.
+ * @return int.
+ */
+
+static int ossl_test_aes128gcm_final(void *vprovctx, unsigned char *out, size_t *outl,
+                                     size_t outsize)
+{
+    int ret;
+
+    *outl = 0;
+    ret = 1;
+    return ret;
+}
+
+/**
+ * @brief Implement ossl test aes128gcm cipher.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param out unsigned char *out.
+ * @param outl size_t *outl.
+ * @param outsize size_t outsize.
+ * @param in const unsigned char *in.
+ * @param inl size_t inl.
+ * @return int.
+ */
+
+static int ossl_test_aes128gcm_cipher(void *vprovctx, unsigned char *out, size_t *outl,
+                                      size_t outsize, const unsigned char *in, size_t inl)
+{
+    PROV_EVP_AES128_GCM_CTX *ctx = (PROV_EVP_AES128_GCM_CTX *)vprovctx;
+
+    return EVP_Cipher(ctx->sub_ctx, out, in, (int) inl);
+}
+
+#define AEAD_FLAGS (PROV_CIPHER_FLAG_AEAD | PROV_CIPHER_FLAG_CUSTOM_IV)
+
+/**
+ * @brief Return aes-128-gcm parameters.
+ *
+ * @param params OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128gcm_get_params(OSSL_PARAM params[])
+{
+    return ossl_cipher_generic_get_params(params, EVP_CIPH_GCM_MODE, AEAD_FLAGS, 128, 8, 96);
+}
+
+/**
+ * @brief Query parameters from the aes-128-gcm context.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param params OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128gcm_get_ctx_params(void *vprovctx, OSSL_PARAM params[])
+{
+    PROV_EVP_AES128_GCM_CTX *ctx = (PROV_EVP_AES128_GCM_CTX *)vprovctx;
+    OSSL_PARAM *p;
+    int ret;
+    uint8_t *tagval = NULL;
+    size_t taglen;
+
+    p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG);
+    if (p != NULL) {
+        if (OSSL_PARAM_get_octet_string_ptr(p, (void *)&tagval, &taglen))
+            memset(tagval, 0, taglen);
+        ret = 1;
+    } else {
+        ret = EVP_CIPHER_CTX_get_params(ctx->sub_ctx, params);
+    }
+
+    return ret;
+
+}
+
+/**
+ * @brief Set parameters on the aes-128-gcm context.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param params const OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128gcm_set_ctx_params(void *vprovctx, const OSSL_PARAM params[])
+{
+    PROV_EVP_AES128_GCM_CTX *ctx = (PROV_EVP_AES128_GCM_CTX *)vprovctx;
+
+    return EVP_CIPHER_CTX_set_params(ctx->sub_ctx, params);
+}
+
+/**
+ * @brief Describe parameters that can be queried aes-128-gcm.
+ *
+ * @param vprovctx void *vprovctx.
+ * @return const OSSL_PARAM *.
+ */
+
+static const OSSL_PARAM *ossl_test_aes128gcm_gettable_params(void *vprovctx)
+{
+    PROV_EVP_AES128_GCM_CTX *ctx = (PROV_EVP_AES128_GCM_CTX *)vprovctx;
+
+    return EVP_CIPHER_gettable_params(EVP_CIPHER_CTX_get0_cipher(ctx->sub_ctx));
+}
+
+/**
+ * @brief aes-128-gcm context parameters that can be queried.
+ *
+ * @param cctx void *cctx.
+ * @param vprovctx void *vprovctx.
+ * @return const OSSL_PARAM *.
+ */
+
+static const OSSL_PARAM *ossl_test_aes128gcm_gettable_ctx_params(void *cctx, void *vprovctx)
+{
+    return ossl_cipher_generic_gettable_ctx_params(cctx, vprovctx);
+}
+
+/**
+ * @brief Describe aes-128-gcm context parameters that can be set.
+ *
+ * @param cctx void *cctx.
+ * @param vprovctx void *vprovctx.
+ * @return const OSSL_PARAM *.
+ */
+
+static const OSSL_PARAM *ossl_test_aes128gcm_settable_ctx_params(void *cctx, void *vprovctx)
+{
+    PROV_EVP_AES128_GCM_CTX *ctx = (PROV_EVP_AES128_GCM_CTX *)vprovctx;
+
+    return EVP_CIPHER_CTX_settable_params(ctx->sub_ctx);
+}
+
+static const OSSL_DISPATCH ossl_testaes128_gcm_functions[] = {
+    { OSSL_FUNC_CIPHER_NEWCTX,
+      (void (*)(void)) ossl_testaes128_gcm_newctx },
+    { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) ossl_test_aes128gcm_freectx },
+    { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) ossl_test_aes128gcm_dupctx },
+    { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))ossl_test_aes128gcm_einit },
+    { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))ossl_test_aes128gcm_dinit },
+    { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))ossl_test_aes128gcm_update },
+    { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))ossl_test_aes128gcm_final },
+    { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))ossl_test_aes128gcm_cipher },
+    { OSSL_FUNC_CIPHER_GET_PARAMS,
+      (void (*)(void)) ossl_test_aes128gcm_get_params },
+    { OSSL_FUNC_CIPHER_GET_CTX_PARAMS,
+      (void (*)(void))ossl_test_aes128gcm_get_ctx_params },
+    { OSSL_FUNC_CIPHER_SET_CTX_PARAMS,
+      (void (*)(void))ossl_test_aes128gcm_set_ctx_params },
+    { OSSL_FUNC_CIPHER_GETTABLE_PARAMS,
+      (void (*)(void))ossl_test_aes128gcm_gettable_params },
+    { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS,
+      (void (*)(void))ossl_test_aes128gcm_gettable_ctx_params },
+    { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS,
+      (void (*)(void))ossl_test_aes128gcm_settable_ctx_params },
+    OSSL_DISPATCH_END
+};
+
+#define NO_PAYLOAD_LENGTH ((size_t)-1)
+
+typedef struct {
+    OSSL_LIB_CTX *libctx;
+    int encrypting;
+    size_t payload_length;
+    unsigned int tls_ver;
+    size_t pad_size;
+} PROV_EVP_AES128_CBC_HMAC_SHA1_CTX;
+
+/**
+ * @brief Allocate and initialize a new aes-128-cbc-hmac-sha1 algorithm context.
+ *
+ * @param provctx void *provctx.
+ * @return a provider aes-128-cbc-hmac-sha1 context as a void pointer.
+ */
+
+static void *ossl_testaes128cbchmacsha1_newctx(void *provctx)
+{
+    PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *new;
+
+    if (!ossl_prov_is_running())
+        return NULL;
+
+    new = OPENSSL_zalloc(sizeof(PROV_EVP_AES128_CBC_HMAC_SHA1_CTX));
+    if (new == NULL)
+        return NULL;
+
+    new->libctx = PROV_LIBCTX_OF(provctx);
+    new->payload_length = NO_PAYLOAD_LENGTH;
+
+    return new;
+}
+
+/**
+ * @brief Release resources and clean up the aes-128-cbc-hmac-sha1 context.
+ *
+ * @param vprovctx void *vprovctx.
+ * @return void.
+ */
+
+static void ossl_test_aes128cbchmacsha1_freectx(void *vprovctx)
+{
+    PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *ctx = (PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *)vprovctx;
+
+    OPENSSL_free(ctx);
+    return;
+}
+
+/**
+ * @brief Duplicate an aes-128-cbc-hmac-sha1 algorithm context.
+ *
+ * @param vprovctx void *vprovctx.
+ * @return a new aes-128-cbc-hmac-sha1 context as a void pointer.
+ */
+
+static void *ossl_test_aes128cbchmacsha1_dupctx(void *vprovctx)
+{
+    PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *ctx = (PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *)vprovctx;
+
+    return OPENSSL_memdup(ctx, sizeof(PROV_EVP_AES128_CBC_HMAC_SHA1_CTX));
+}
+
+/**
+ * @brief Initialize the aes-128-cbc-hmac-sha1 context for encryption.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param key const unsigned char *key.
+ * @param keylen size_t keylen.
+ * @param iv const unsigned char *iv.
+ * @param ivlen size_t ivlen.
+ * @param params const OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128cbchmacsha1_einit(void *vprovctx, const unsigned char *key,
+                                             size_t keylen, const unsigned char *iv,
+                                             size_t ivlen, const OSSL_PARAM params[])
+{
+    PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *ctx = (PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *)vprovctx;
+
+    ctx->payload_length = NO_PAYLOAD_LENGTH;
+    ctx->encrypting = 1;
+    return 1;
+}
+
+/**
+ * @brief Initialize the aes-128-cbc-hmac-sha1 context for encryption.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param key const unsigned char *key.
+ * @param keylen size_t keylen.
+ * @param iv const unsigned char *iv.
+ * @param ivlen size_t ivlen.
+ * @param params const OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128cbchmacsha1_dinit(void *vprovctx, const unsigned char *key,
+                                             size_t keylen, const unsigned char *iv,
+                                             size_t ivlen, const OSSL_PARAM params[])
+{
+    PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *ctx = (PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *)vprovctx;
+
+    ctx->payload_length = NO_PAYLOAD_LENGTH;
+    ctx->encrypting = 0;
+    return 1;
+}
+
+/**
+ * @brief do en/decryption for aes-128-cbc-hmac-sha1
+ *
+ * @param vprovctx void *vprovctx.
+ * @param out unsigned char *out.
+ * @param outl size_t *outl.
+ * @param outsize size_t outsize.
+ * @param in const unsigned char *in.
+ * @param inl size_t inl.
+ * @return int.
+ */
+
+static int ossl_test_aes128cbchmacsha1_update(void *vprovctx, unsigned char *out, size_t *outl,
+                                              size_t outsize, const unsigned char *in,
+                                              size_t inl)
+{
+    PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *ctx = (PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *)vprovctx;
+    size_t l;
+    size_t plen = ctx->payload_length;
+    size_t orig_inl = inl;
+    const unsigned char *outtmp;
+
+    if (ctx->encrypting) {
+        if (plen == NO_PAYLOAD_LENGTH)
+            plen = inl;
+        else if (inl !=
+                 ((plen + SHA_DIGEST_LENGTH +
+                   AES_BLOCK_SIZE) & (-AES_BLOCK_SIZE)))
+            return 0;
+
+        memmove(out, in, plen);
+
+        if (plen != inl) {      /* "TLS" mode of operation */
+            /* calculate HMAC and append it to payload */
+            fill_known_data(out + plen, SHA_DIGEST_LENGTH);
+
+            /* pad the payload|hmac */
+            plen += SHA_DIGEST_LENGTH;
+            for (l = (unsigned int)(inl - plen - 1); plen < inl; plen++)
+                out[plen] = (unsigned char)l;
+        }
+    } else {
+        /* decrypt HMAC|padding at once */
+        memmove(out, in, inl);
+
+        if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */
+            unsigned int maxpad, pad;
+
+            if (ctx->tls_ver >= TLS1_1_VERSION) {
+                if (inl < (AES_BLOCK_SIZE + SHA_DIGEST_LENGTH + 1))
+                    return 0;
+
+                /* omit explicit iv */
+                in += AES_BLOCK_SIZE;
+                inl -= AES_BLOCK_SIZE;
+            } else {
+                if (inl < (SHA_DIGEST_LENGTH + 1))
+                    return 0;
+            }
+
+            outtmp = out + AES_BLOCK_SIZE;
+            /* figure out payload length */
+            pad = outtmp[inl - 1];
+            maxpad = (unsigned int)(inl - (SHA_DIGEST_LENGTH + 1));
+            if (pad > maxpad)
+                return 0;
+            for (plen = inl - pad - 1; plen < inl; plen++)
+                if (outtmp[plen] != pad)
+                    return 0;
+            /*
+             * We need to return the actual dummied up payload of this
+             * operation, so reduce the length of the output by the padding
+             * size that we just stripped as well as the leading IV, which
+             * is the first AES_BLOCK_SIZE bytes
+             */
+            orig_inl -= pad + 1 + SHA_DIGEST_LENGTH;
+            orig_inl -= AES_BLOCK_SIZE;
+        }
+    }
+    *outl = orig_inl;
+    return 1;
+}
+
+/**
+ * @brief finalize aes-128-cbc-hmac-sha1 en/decrypt operation
+ *
+ * @param vprovctx void *vprovctx.
+ * @param out unsigned char *out.
+ * @param outl size_t *outl.
+ * @param outsize size_t outsize.
+ * @return int.
+ */
+
+static int ossl_test_aes128cbchmacsha1_final(void *vprovctx, unsigned char *out, size_t *outl,
+                                             size_t outsize)
+{
+    /*
+     * Since we don't do any real en/decryption in this alg, this is a no-op
+     * so just return success
+     */
+    return 1;
+}
+
+/**
+ * @brief Implement ossl test aes128cbchmacsha1 cipher.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param out unsigned char *out.
+ * @param outl size_t *outl.
+ * @param outsize size_t outsize.
+ * @param in const unsigned char *in.
+ * @param inl size_t inl.
+ * @return int.
+ */
+
+static int ossl_test_aes128cbchmacsha1_cipher(void *vprovctx,
+                                              unsigned char *out, size_t *outl,
+                                              size_t outsize, const unsigned char *in, size_t inl)
+{
+    return 1;
+}
+
+#define AES_CBC_HMAC_SHA_FLAGS (PROV_CIPHER_FLAG_AEAD | PROV_CIPHER_FLAG_TLS1_MULTIBLOCK)
+/**
+ * @brief Return aes-128-cbc-hmac-sha1 gettable parameters.
+ *
+ * @param params OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128cbchmacsha1_get_params(OSSL_PARAM params[])
+{
+    int ret;
+
+    ret = ossl_cipher_generic_get_params(params, EVP_CIPH_CBC_MODE,
+                                         AES_CBC_HMAC_SHA_FLAGS, 128, 128, 128);
+
+    return ret;
+}
+
+/**
+ * @brief Query aes-128-cbc-hmac-sha1 context parameters.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param params OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128cbchmacsha1_get_ctx_params(void *vprovctx, OSSL_PARAM params[])
+{
+    PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *ctx = (PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *)vprovctx;
+    OSSL_PARAM *p;
+
+    /*
+     * lifted from aes_get_ctx_params
+     */
+#if !defined(OPENSSL_NO_MULTIBLOCK)
+    p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_MAX_BUFSIZE);
+    if (p != NULL) {
+        /*
+         * Don't know how to handle any of these
+         */
+        ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+        return 0;
+    }
+
+    p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_INTERLEAVE);
+    if (p != NULL) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+        return 0;
+    }
+
+    p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_AAD_PACKLEN);
+    if (p != NULL) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+        return 0;
+    }
+
+    p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC_LEN);
+    if (p != NULL) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+        return 0;
+    }
+#endif /* !defined(OPENSSL_NO_MULTIBLOCK) */
+
+    p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD);
+    if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->pad_size)) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+        return 0;
+    }
+    p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN);
+    if (p != NULL && !OSSL_PARAM_set_size_t(p, 128 / 8)) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+        return 0;
+    }
+    p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN);
+    if (p != NULL && !OSSL_PARAM_set_size_t(p, 128 / 8)) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+        return 0;
+    }
+    p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV);
+    if (p != NULL) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+        return 0;
+    }
+    p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_UPDATED_IV);
+    if (p != NULL) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+        return 0;
+    }
+
+    return 1;
+}
+
+/**
+ * @brief Set aes-128-cbc-hmac-sha1 context parameters.
+ *
+ * @param vprovctx void *vprovctx.
+ * @param params const OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int ossl_test_aes128cbchmacsha1_set_ctx_params(void *vprovctx, const OSSL_PARAM params[])
+{
+    PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *ctx = (PROV_EVP_AES128_CBC_HMAC_SHA1_CTX *)vprovctx;
+    OSSL_PARAM *p;
+    uint8_t *val;
+    size_t vlen;
+    unsigned int len;
+
+    p = OSSL_PARAM_locate((OSSL_PARAM *)params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD);
+    if (p != NULL) {
+        OSSL_PARAM_get_octet_string_ptr(p, (const void **)&val, &vlen);
+        len = val[EVP_AEAD_TLS1_AAD_LEN - 2] << 8 | val[EVP_AEAD_TLS1_AAD_LEN - 1];
+        ctx->tls_ver = val[EVP_AEAD_TLS1_AAD_LEN - 4] << 8 | val[EVP_AEAD_TLS1_AAD_LEN -3];
+
+        if (ctx->encrypting) {
+            ctx->payload_length = len;
+            if (ctx->tls_ver >= TLS1_1_VERSION) {
+                if (len < AES_BLOCK_SIZE)
+                    return 0;
+                len -= AES_BLOCK_SIZE;
+                val[EVP_AEAD_TLS1_AAD_LEN - 2] = len >> 8;
+                val[EVP_AEAD_TLS1_AAD_LEN - 1] = len;
+                ctx->pad_size = ((len + SHA_DIGEST_LENGTH +
+                                  AES_BLOCK_SIZE) & (-AES_BLOCK_SIZE)) - len;
+            }
+        } else {
+            ctx->payload_length = EVP_AEAD_TLS1_AAD_LEN;
+            ctx->pad_size = SHA_DIGEST_LENGTH;
+        }
+
+    }
+
+    return 1;
+}
+
+/**
+ * @brief Describe parameters that can be queried for aes-128-cbc-hmac-sha1.
+ *
+ * @param vprovctx void *vprovctx.
+ * @return const OSSL_PARAM *.
+ */
+
+static const OSSL_PARAM *ossl_test_aes128cbchmacsha1_gettable_params(void *vprovctx)
+{
+    return NULL;
+}
+
+/**
+ * @brief Describe context parameters that can be queried for an aes-128-cbc-hamc-sha1 ctx.
+ *
+ * @param cctx void *cctx.
+ * @param vprovctx void *vprovctx.
+ * @return const OSSL_PARAM *.
+ */
+
+static const OSSL_PARAM *ossl_test_aes128cbchmacsha1_gettable_ctx_params(void *cctx, void *vprovctx)
+{
+    return ossl_cipher_generic_gettable_ctx_params(cctx, vprovctx);
+}
+
+/**
+ * @brief Describe context parameters that can be set on an aes-128-cbc-hmac-sha1 ctx.
+ *
+ * @param cctx void *cctx.
+ * @param vprovctx void *vprovctx.
+ * @return const OSSL_PARAM *.
+ */
+
+static const OSSL_PARAM *ossl_test_aes128cbchmacsha1_settable_ctx_params(void *cctx, void *vprovctx)
+{
+    return NULL;
+}
+
+static const OSSL_DISPATCH ossl_testaes128cbchmacsha1_functions[] = {
+    { OSSL_FUNC_CIPHER_NEWCTX,
+      (void (*)(void)) ossl_testaes128cbchmacsha1_newctx },
+    { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) ossl_test_aes128cbchmacsha1_freectx },
+    { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) ossl_test_aes128cbchmacsha1_dupctx },
+    { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))ossl_test_aes128cbchmacsha1_einit },
+    { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))ossl_test_aes128cbchmacsha1_dinit },
+    { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))ossl_test_aes128cbchmacsha1_update },
+    { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))ossl_test_aes128cbchmacsha1_final },
+    { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))ossl_test_aes128cbchmacsha1_cipher },
+    { OSSL_FUNC_CIPHER_GET_PARAMS,
+      (void (*)(void)) ossl_test_aes128cbchmacsha1_get_params },
+    { OSSL_FUNC_CIPHER_GET_CTX_PARAMS,
+      (void (*)(void))ossl_test_aes128cbchmacsha1_get_ctx_params },
+    { OSSL_FUNC_CIPHER_SET_CTX_PARAMS,
+      (void (*)(void))ossl_test_aes128cbchmacsha1_set_ctx_params },
+    { OSSL_FUNC_CIPHER_GETTABLE_PARAMS,
+      (void (*)(void))ossl_test_aes128cbchmacsha1_gettable_params },
+    { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS,
+      (void (*)(void))ossl_test_aes128cbchmacsha1_gettable_ctx_params },
+    { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS,
+      (void (*)(void))ossl_test_aes128cbchmacsha1_settable_ctx_params },
+    OSSL_DISPATCH_END
+};
+
+static const OSSL_ALGORITHM ossltest_ciphers[] = {
+    ALG(PROV_NAMES_AES_128_CBC, ossl_testaes128_cbc_functions),
+    ALG(PROV_NAMES_AES_128_GCM, ossl_testaes128_gcm_functions),
+    ALG(PROV_NAMES_AES_128_CBC_HMAC_SHA1, ossl_testaes128cbchmacsha1_functions),
+    {NULL, NULL, NULL}
+};
+
+typedef struct ossl_test_rand_ctx {
+    size_t unused;
+} OSSL_TEST_RAND_CTX;
+
+/**
+ * @brief Implement drbg ctr new wrapper.
+ *
+ * @param provctx void *provctx.
+ * @param parent void *parent.
+ * @param parent_dispatch const OSSL_DISPATCH *parent_dispatch.
+ * @return void *.
+ */
+
+static void *drbg_ctr_new_wrapper(void *provctx, void *parent,
+                                  const OSSL_DISPATCH *parent_dispatch)
+{
+    return OPENSSL_zalloc(sizeof(OSSL_TEST_RAND_CTX));
+}
+
+/**
+ * @brief Release resources and clean up the context.
+ *
+ * @param vdrbg void *vdrbg.
+ * @return void.
+ */
+
+static void drbg_ctr_free(void *vdrbg)
+{
+    OPENSSL_free(vdrbg);
+}
+
+/**
+ * @brief Instantiate the CTR DRBG with the given inputs.
+ *
+ * @param vdrbg void *vdrbg.
+ * @param strength unsigned int strength.
+ * @param prediction_resistance int prediction_resistance.
+ * @param pstr const unsigned char *pstr.
+ * @param pstr_len size_t pstr_len.
+ * @param params const OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int drbg_ctr_instantiate_wrapper(void *vdrbg, unsigned int strength,
+                                        int prediction_resistance,
+                                        const unsigned char *pstr,
+                                        size_t pstr_len,
+                                        const OSSL_PARAM params[])
+{
+    return 1;
+}
+
+/**
+ * @brief Instantiate the CTR DRBG with the given inputs.
+ *
+ * @param vdrbg void *vdrbg.
+ * @return int.
+ */
+
+static int drbg_ctr_uninstantiate_wrapper(void *vdrbg)
+{
+    return 1;
+}
+
+/**
+ * @brief Generate pseudo-random bytes from the CTR DRBG.
+ *
+ * @param vdrbg void *vdrbg.
+ * @param out unsigned char *out.
+ * @param outlen size_t outlen.
+ * @param strength unsigned int strength.
+ * @param prediction_resistance int prediction_resistance.
+ * @param adin const unsigned char *adin.
+ * @param adin_len size_t adin_len.
+ * @return int.
+ */
+
+static int drbg_ctr_generate_wrapper(void *vdrbg, unsigned char *out,
+                                     size_t outlen, unsigned int strength,
+                                     int prediction_resistance,
+                                     const unsigned char *adin, size_t adin_len)
+{
+    unsigned char val = 1;
+    size_t copylen = 0;
+
+    while (copylen < outlen) {
+        *out++ = val++;
+        copylen++;
+    }
+
+    return 1;
+}
+
+/**
+ * @brief Reseed the CTR DRBG with fresh entropy.
+ *
+ * @param vdrbg void *vdrbg.
+ * @param prediction_resistance int prediction_resistance.
+ * @param ent const unsigned char *ent.
+ * @param ent_len size_t ent_len.
+ * @param adin const unsigned char *adin.
+ * @param adin_len size_t adin_len.
+ * @return int.
+ */
+
+static int drbg_ctr_reseed_wrapper(void *vdrbg, int prediction_resistance,
+                                   const unsigned char *ent, size_t ent_len,
+                                   const unsigned char *adin, size_t adin_len)
+{
+    return 1;
+}
+
+/**
+ * @brief Enable internal locking for thread safety.
+ *
+ * @param vctx void *vctx.
+ * @return int.
+ */
+
+static int ossl_drbg_enable_locking(void *vctx)
+{
+    return 1;
+}
+
+/**
+ * @brief Acquire the internal lock.
+ *
+ * @param vctx void *vctx.
+ * @return int.
+ */
+
+static int ossl_drbg_lock(void *vctx)
+{
+    return 1;
+}
+
+/**
+ * @brief Release the internal lock.
+ *
+ * @param vctx void *vctx.
+ * @return void.
+ */
+
+static void ossl_drbg_unlock(void *vctx)
+{
+    return;
+}
+
+/**
+ * @brief Describe context parameters that can be set.
+ *
+ * @param vctx ossl_unused void *vctx.
+ * @param provctx ossl_unused void *provctx.
+ * @return const OSSL_PARAM *.
+ */
+
+static const OSSL_PARAM *drbg_ctr_settable_ctx_params(ossl_unused void *vctx,
+                                                      ossl_unused void *provctx)
+{
+    return NULL;
+}
+
+/**
+ * @brief Set parameters on the algorithm context.
+ *
+ * @param vctx void *vctx.
+ * @param params const OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int drbg_ctr_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+    return 1;
+}
+
+/**
+ * @brief Describe context parameters that can be queried.
+ *
+ * @param vctx ossl_unused void *vctx.
+ * @param provctx ossl_unused void *provctx.
+ * @return const OSSL_PARAM *.
+ */
+
+static const OSSL_PARAM *drbg_ctr_gettable_ctx_params(ossl_unused void *vctx,
+                                                      ossl_unused void *provctx)
+{
+    return NULL;
+}
+
+/**
+ * @brief Query parameters from the algorithm context.
+ *
+ * @param vdrbg void *vdrbg.
+ * @param params OSSL_PARAM params[].
+ * @return int.
+ */
+
+static int drbg_ctr_get_ctx_params(void *vdrbg, OSSL_PARAM params[])
+{
+    OSSL_PARAM *p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST);
+
+    if (p != NULL)
+        OSSL_PARAM_set_size_t(p, (size_t)(1 << 16));
+
+    return 1;
+}
+
+/**
+ * @brief Verify that sensitive buffers are cleared to zero.
+ *
+ * @param vdrbg void *vdrbg.
+ * @return int.
+ */
+
+static int drbg_ctr_verify_zeroization(void *vdrbg)
+{
+    return 1;
+}
+
+/**
+ * @brief Return the stored test seed buffer if present.
+ *
+ * @param vdrbg void *vdrbg.
+ * @param pout unsigned char **pout.
+ * @param entropy int entropy.
+ * @param min_len size_t min_len.
+ * @param max_len size_t max_len.
+ * @param prediction_resistance int prediction_resistance.
+ * @param adin const unsigned char *adin.
+ * @param adin_len size_t adin_len.
+ * @return size_t.
+ */
+
+static size_t ossl_drbg_get_seed(void *vdrbg, unsigned char **pout,
+                                 int entropy, size_t min_len,
+                                 size_t max_len, int prediction_resistance,
+                                 const unsigned char *adin, size_t adin_len)
+{
+    size_t needed = entropy;
+
+    if (needed < min_len)
+        needed = min_len;
+    if (needed > max_len)
+        needed = max_len;
+    return needed;
+}
+
+/**
+ * @brief Clear any stored test seed buffer.
+ *
+ * @param vdrbg ossl_unused void *vdrbg.
+ * @param out unsigned char *out.
+ * @param outlen size_t outlen.
+ * @return void.
+ */
+
+static void ossl_drbg_clear_seed(ossl_unused void *vdrbg,
+                                 unsigned char *out, size_t outlen)
+{
+    return;
+}
+
+static const OSSL_DISPATCH ossl_test_drbg_ctr_functions[] = {
+    { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))drbg_ctr_new_wrapper },
+    { OSSL_FUNC_RAND_FREECTX, (void(*)(void))drbg_ctr_free },
+    { OSSL_FUNC_RAND_INSTANTIATE,
+      (void(*)(void))drbg_ctr_instantiate_wrapper },
+    { OSSL_FUNC_RAND_UNINSTANTIATE,
+      (void(*)(void))drbg_ctr_uninstantiate_wrapper },
+    { OSSL_FUNC_RAND_GENERATE, (void(*)(void))drbg_ctr_generate_wrapper },
+    { OSSL_FUNC_RAND_RESEED, (void(*)(void))drbg_ctr_reseed_wrapper },
+    { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))ossl_drbg_enable_locking },
+    { OSSL_FUNC_RAND_LOCK, (void(*)(void))ossl_drbg_lock },
+    { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))ossl_drbg_unlock },
+    { OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS,
+      (void(*)(void))drbg_ctr_settable_ctx_params },
+    { OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))drbg_ctr_set_ctx_params },
+    { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS,
+      (void(*)(void))drbg_ctr_gettable_ctx_params },
+    { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))drbg_ctr_get_ctx_params },
+    { OSSL_FUNC_RAND_VERIFY_ZEROIZATION,
+      (void(*)(void))drbg_ctr_verify_zeroization },
+    { OSSL_FUNC_RAND_GET_SEED, (void(*)(void))ossl_drbg_get_seed },
+    { OSSL_FUNC_RAND_CLEAR_SEED, (void(*)(void))ossl_drbg_clear_seed },
+    OSSL_DISPATCH_END
+};
+
+static const OSSL_ALGORITHM ossltest_rands[] = {
+    ALG(PROV_NAMES_CTR_DRBG, ossl_test_drbg_ctr_functions),
+    {NULL, NULL, NULL}
+};
+
+/**
+ * @brief Implement ossltest query.
+ *
+ * @param provctx void *provctx.
+ * @param operation_id int operation_id.
+ * @param no_cache int *no_cache.
+ * @return const OSSL_ALGORITHM *.
+ */
+
+static const OSSL_ALGORITHM *ossltest_query(void *provctx, int operation_id,
+                                            int *no_cache)
+{
+    *no_cache = 0;
+    switch (operation_id) {
+    case OSSL_OP_DIGEST:
+        return ossltest_digests;
+    case OSSL_OP_CIPHER:
+        return ossltest_ciphers;
+    case OSSL_OP_RAND:
+        return ossltest_rands;
+    }
+    return NULL;
+}
+
+static const OSSL_DISPATCH ossltest_dispatch_table[] = {
+    { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))ossltest_teardown },
+    { OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, (void (*)(void))ossltest_gettable_params },
+    { OSSL_FUNC_PROVIDER_GET_PARAMS, (void (*)(void))ossltest_get_params },
+    { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))ossltest_query },
+    OSSL_DISPATCH_END
+};
+
+OSSL_provider_init_fn OSSL_provider_init_int;
+/**
+ * @brief Initialize the context or operation state.
+ *
+ * @param handle const OSSL_CORE_HANDLE *handle.
+ * @param in const OSSL_DISPATCH *in.
+ * @param out const OSSL_DISPATCH **out.
+ * @param provctx void **provctx.
+ * @return int.
+ */
+int OSSL_provider_init(const OSSL_CORE_HANDLE *handle,
+                       const OSSL_DISPATCH *in,
+                       const OSSL_DISPATCH **out,
+                       void **provctx)
+{
+    OSSL_LIB_CTX *libctx = NULL;
+
+    if ((*provctx = ossl_prov_ctx_new()) == NULL
+        || (libctx = OSSL_LIB_CTX_new_child(handle, in)) == NULL) {
+        OSSL_LIB_CTX_free(libctx);
+        ossltest_teardown(*provctx);
+        *provctx = NULL;
+        return 0;
+    }
+
+    ossl_prov_ctx_set0_libctx(*provctx, libctx);
+    ossl_prov_ctx_set0_handle(*provctx, handle);
+
+    *out = ossltest_dispatch_table;
+
+    return 1;
+}