[RFC PATCH] openssl: make the patches QUILT-friendly

Rosen Penev rosenp at gmail.com
Fri Mar 26 19:31:40 GMT 2021


On Fri, Mar 26, 2021 at 11:56 AM Eneas U de Queiroz
<cotequeiroz at gmail.com> wrote:
>
> The patches in this package are all made by git format-patches.  If one
> were to run 'make package/openssl/{refresh,update}', then things will
> not work as expected, because quilt QUILT does not deal well with
> patches that rename files.  For openssl, the problematic patch is
> 430-e_devcrypto-make-the-dev-crypto-engine-dynamic.patch.
>
> So, I've generated a new patch with 'git format-patch --no-renames', and
> then 'make package/openssl/{refresh,update}'.
NAK. This just bloats the patches for no good reason. It also makes it
harder to deal with upstream changes.

I know that you're fairly competent when dealing with this, but think
about it from a drive by contributor. Getting a setup to properly
refresh patches like these is difficult.
>
> Signed-off-by: Eneas U de Queiroz <cotequeiroz at gmail.com>
> ---
>
> While I really prefer to leave the git-formatted patches as they are, I
> know quilt is the preferred way of handling patches in OpenWRT, so I'm
> presenting this as RFC, so the core developers can decide.
>
> ldir has made a similar commit e27ef2da0d, and then reverted it right away
> in bbb9c1c2be, and I don't know why.
>
> neheb proposed a patch [1] that does the file renaming in Build/Prepare, so
> that it is easier to use quilt while refreshing patches after a package
> bump.  It has an undesirable side-effect of not running the renaming
> portion at all when using QUILT, resulting in a build failure.
>
> Some packages in the packages feed are skipping build steps when running
> with QUILT, to speed up automatic refresh of patches, and I've been
> fixing them as I stumble upon some of the failures.
>
> At least to me, being able to quickly build with QUILT=1, without having
> to start from scratch and go through dependencies is an immensively
> useful feature that I would not trade for having tidier patches.
>
> For this package, one could rename the files in Build/Configure when
> compiling with QUILT without a problem.  So, if desired, it could be
> done neheb's way instead.
>
> In my opinion, QUILT is not particularly useful for rebasing large
> changes, such as the engine patches here.  So even if neheb's proposal
> has a nice intention, it is not appropriate for this package.
>
> If the motivation is just to run make package/openssl/{refresh,update},
> perhaps automatically to keep patches tidy, then this patch will
> suffice.
>
> Cheers,
>
> Eneas
>
> [1] https://patchwork.ozlabs.org/project/openwrt/patch/20210326092548.14019-1-rosenp@gmail.com/
>
> diff --git a/package/libs/openssl/Makefile b/package/libs/openssl/Makefile
> index 7ab4c6ccd0..458b064f13 100644
> --- a/package/libs/openssl/Makefile
> +++ b/package/libs/openssl/Makefile
> @@ -11,7 +11,7 @@ PKG_NAME:=openssl
>  PKG_BASE:=1.1.1
>  PKG_BUGFIX:=k
>  PKG_VERSION:=$(PKG_BASE)$(PKG_BUGFIX)
> -PKG_RELEASE:=1
> +PKG_RELEASE:=2
>  PKG_USE_MIPS16:=0
>  ENGINES_DIR=engines-1.1
>
> diff --git a/package/libs/openssl/patches/100-Configure-afalg-support.patch b/package/libs/openssl/patches/100-Configure-afalg-support.patch
> index 98944103b5..2ae5938bdc 100644
> --- a/package/libs/openssl/patches/100-Configure-afalg-support.patch
> +++ b/package/libs/openssl/patches/100-Configure-afalg-support.patch
> @@ -1,4 +1,4 @@
> -From 559fbff13af9ce2fbc0b9bc5727a7323e1db6217 Mon Sep 17 00:00:00 2001
> +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
>  From: Eneas U de Queiroz <cote2004-github at yahoo.com>
>  Date: Thu, 27 Sep 2018 08:29:21 -0300
>  Subject: Do not use host kernel version to disable AFALG
> @@ -8,11 +8,9 @@ version to disable building the AFALG engine on openwrt targets.
>
>  Signed-off-by: Eneas U de Queiroz <cote2004-github at yahoo.com>
>
> -diff --git a/Configure b/Configure
> -index 5a699836f3..74d057c219 100755
>  --- a/Configure
>  +++ b/Configure
> -@@ -1545,7 +1545,9 @@ unless ($disabled{"crypto-mdebug-backtrace"})
> +@@ -1545,7 +1545,9 @@ unless ($disabled{"crypto-mdebug-backtra
>
>   unless ($disabled{afalgeng}) {
>       $config{afalgeng}="";
> diff --git a/package/libs/openssl/patches/110-openwrt_targets.patch b/package/libs/openssl/patches/110-openwrt_targets.patch
> index d0530b4661..50a9ebe2d6 100644
> --- a/package/libs/openssl/patches/110-openwrt_targets.patch
> +++ b/package/libs/openssl/patches/110-openwrt_targets.patch
> @@ -1,4 +1,4 @@
> -From 3d43acc6068f00dbfc0c9a06355e2c8f7d302d0f Mon Sep 17 00:00:00 2001
> +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
>  From: Eneas U de Queiroz <cote2004-github at yahoo.com>
>  Date: Thu, 27 Sep 2018 08:30:24 -0300
>  Subject: Add openwrt targets
> @@ -7,9 +7,6 @@ Targets are named: linux-$(CONFIG_ARCH)-openwrt
>
>  Signed-off-by: Eneas U de Queiroz <cote2004-github at yahoo.com>
>
> -diff --git a/Configurations/25-openwrt.conf b/Configurations/25-openwrt.conf
> -new file mode 100644
> -index 0000000000..86a86d31e4
>  --- /dev/null
>  +++ b/Configurations/25-openwrt.conf
>  @@ -0,0 +1,48 @@
> diff --git a/package/libs/openssl/patches/120-strip-cflags-from-binary.patch b/package/libs/openssl/patches/120-strip-cflags-from-binary.patch
> index 7faec9ab88..90282706d1 100644
> --- a/package/libs/openssl/patches/120-strip-cflags-from-binary.patch
> +++ b/package/libs/openssl/patches/120-strip-cflags-from-binary.patch
> @@ -1,4 +1,4 @@
> -From 4ad8f2fe6bf3b91df7904fcbe960e5fdfca36336 Mon Sep 17 00:00:00 2001
> +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
>  From: Eneas U de Queiroz <cote2004-github at yahoo.com>
>  Date: Thu, 27 Sep 2018 08:31:38 -0300
>  Subject: Avoid exposing build directories
> @@ -8,11 +8,9 @@ OpenSSL_version(OPENSSL_CFLAGS), or running openssl version -a
>
>  Signed-off-by: Eneas U de Queiroz <cote2004-github at yahoo.com>
>
> -diff --git a/crypto/build.info b/crypto/build.info
> -index 2c619c62e8..893128345a 100644
>  --- a/crypto/build.info
>  +++ b/crypto/build.info
> -@@ -10,7 +10,7 @@ EXTRA=  ../ms/uplink-x86.pl ../ms/uplink.c ../ms/applink.c \
> +@@ -10,7 +10,7 @@ EXTRA=  ../ms/uplink-x86.pl ../ms/uplink
>           ppccpuid.pl pariscid.pl alphacpuid.pl arm64cpuid.pl armv4cpuid.pl
>
>   DEPEND[cversion.o]=buildinf.h
> diff --git a/package/libs/openssl/patches/130-dont-build-tests-fuzz.patch b/package/libs/openssl/patches/130-dont-build-tests-fuzz.patch
> index 7f33cb9dae..baf8bca9e1 100644
> --- a/package/libs/openssl/patches/130-dont-build-tests-fuzz.patch
> +++ b/package/libs/openssl/patches/130-dont-build-tests-fuzz.patch
> @@ -1,4 +1,4 @@
> -From ba2fe646f2d9104a18b066e43582154049e9ffcb Mon Sep 17 00:00:00 2001
> +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
>  From: Eneas U de Queiroz <cote2004-github at yahoo.com>
>  Date: Thu, 27 Sep 2018 08:34:38 -0300
>  Subject: Do not build tests and fuzz directories
> @@ -7,11 +7,9 @@ This shortens build time.
>
>  Signed-off-by: Eneas U de Queiroz <cote2004-github at yahoo.com>
>
> -diff --git a/Configure b/Configure
> -index 74d057c219..5813e9f8fe 100755
>  --- a/Configure
>  +++ b/Configure
> -@@ -318,7 +318,7 @@ my $auto_threads=1;    # enable threads automatically? true by default
> +@@ -318,7 +318,7 @@ my $auto_threads=1;    # enable threads
>   my $default_ranlib;
>
>   # Top level directories to build
> diff --git a/package/libs/openssl/patches/140-allow-prefer-chacha20.patch b/package/libs/openssl/patches/140-allow-prefer-chacha20.patch
> index b293db28f7..58a9d7400c 100644
> --- a/package/libs/openssl/patches/140-allow-prefer-chacha20.patch
> +++ b/package/libs/openssl/patches/140-allow-prefer-chacha20.patch
> @@ -1,4 +1,4 @@
> -From 4f7ab2040bb71f03a8f8388911144559aa2a5b60 Mon Sep 17 00:00:00 2001
> +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
>  From: Eneas U de Queiroz <cote2004-github at yahoo.com>
>  Date: Thu, 27 Sep 2018 08:44:39 -0300
>  Subject: Add OPENSSL_PREFER_CHACHA_OVER_GCM option
> @@ -14,8 +14,6 @@ when the client has it on top of its ciphersuite preference.
>
>  Signed-off-by: Eneas U de Queiroz <cote2004-github at yahoo.com>
>
> -diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
> -index 6724ccf2d2..96d959427e 100644
>  --- a/include/openssl/ssl.h
>  +++ b/include/openssl/ssl.h
>  @@ -173,9 +173,15 @@ extern "C" {
> @@ -37,11 +35,9 @@ index 6724ccf2d2..96d959427e 100644
>   # else
>   #  define TLS_DEFAULT_CIPHERSUITES "TLS_AES_256_GCM_SHA384:" \
>                                      "TLS_AES_128_GCM_SHA256"
> -diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
> -index 27a1b2ec68..7039811323 100644
>  --- a/ssl/ssl_ciph.c
>  +++ b/ssl/ssl_ciph.c
> -@@ -1467,11 +1467,29 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
> +@@ -1467,11 +1467,29 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_
>       ssl_cipher_apply_rule(0, SSL_kECDHE, 0, 0, 0, 0, 0, CIPHER_DEL, -1, &head,
>                             &tail);
>
> @@ -71,7 +67,7 @@ index 27a1b2ec68..7039811323 100644
>
>       /*
>        * ...and generally, our preferred cipher is AES.
> -@@ -1527,7 +1545,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
> +@@ -1527,7 +1545,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_
>        * Within each group, ciphers remain sorted by strength and previous
>        * preference, i.e.,
>        * 1) ECDHE > DHE
> diff --git a/package/libs/openssl/patches/400-eng_devcrypto-save-ioctl-if-EVP_MD_.FLAG_ONESHOT.patch b/package/libs/openssl/patches/400-eng_devcrypto-save-ioctl-if-EVP_MD_.FLAG_ONESHOT.patch
> index 84c68b16a2..ed8204c339 100644
> --- a/package/libs/openssl/patches/400-eng_devcrypto-save-ioctl-if-EVP_MD_.FLAG_ONESHOT.patch
> +++ b/package/libs/openssl/patches/400-eng_devcrypto-save-ioctl-if-EVP_MD_.FLAG_ONESHOT.patch
> @@ -1,4 +1,4 @@
> -From f14345422747a495a52f9237a43b8be189f21912 Mon Sep 17 00:00:00 2001
> +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
>  From: Eneas U de Queiroz <cote2004-github at yahoo.com>
>  Date: Mon, 5 Nov 2018 15:54:17 -0200
>  Subject: eng_devcrypto: save ioctl if EVP_MD_..FLAG_ONESHOT
> @@ -14,8 +14,6 @@ Reviewed-by: Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
>  Reviewed-by: Richard Levitte <levitte at openssl.org>
>  (Merged from https://github.com/openssl/openssl/pull/7585)
>
> -diff --git a/crypto/engine/eng_devcrypto.c b/crypto/engine/eng_devcrypto.c
> -index a727c6f646..a2c9a966f7 100644
>  --- a/crypto/engine/eng_devcrypto.c
>  +++ b/crypto/engine/eng_devcrypto.c
>  @@ -461,6 +461,7 @@ struct digest_ctx {
> @@ -26,7 +24,7 @@ index a727c6f646..a2c9a966f7 100644
>   };
>
>   static const struct digest_data_st {
> -@@ -564,12 +565,15 @@ static int digest_update(EVP_MD_CTX *ctx, const void *data, size_t count)
> +@@ -564,12 +565,15 @@ static int digest_update(EVP_MD_CTX *ctx
>       if (digest_ctx == NULL)
>           return 0;
>
> @@ -46,7 +44,7 @@ index a727c6f646..a2c9a966f7 100644
>   }
>
>   static int digest_final(EVP_MD_CTX *ctx, unsigned char *md)
> -@@ -579,7 +583,10 @@ static int digest_final(EVP_MD_CTX *ctx, unsigned char *md)
> +@@ -579,7 +583,10 @@ static int digest_final(EVP_MD_CTX *ctx,
>
>       if (md == NULL || digest_ctx == NULL)
>           return 0;
> diff --git a/package/libs/openssl/patches/410-eng_devcrypto-add-configuration-options.patch b/package/libs/openssl/patches/410-eng_devcrypto-add-configuration-options.patch
> index 8745364cf2..bad7a37256 100644
> --- a/package/libs/openssl/patches/410-eng_devcrypto-add-configuration-options.patch
> +++ b/package/libs/openssl/patches/410-eng_devcrypto-add-configuration-options.patch
> @@ -1,4 +1,4 @@
> -From 1c2fabcdb34e436286b4a8760cfbfbff11ea551a Mon Sep 17 00:00:00 2001
> +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
>  From: Eneas U de Queiroz <cote2004-github at yahoo.com>
>  Date: Sat, 3 Nov 2018 15:41:10 -0300
>  Subject: eng_devcrypto: add configuration options
> @@ -13,8 +13,6 @@ Reviewed-by: Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
>  Reviewed-by: Richard Levitte <levitte at openssl.org>
>  (Merged from https://github.com/openssl/openssl/pull/7585)
>
> -diff --git a/crypto/engine/eng_devcrypto.c b/crypto/engine/eng_devcrypto.c
> -index a2c9a966f7..5ec38ca8f3 100644
>  --- a/crypto/engine/eng_devcrypto.c
>  +++ b/crypto/engine/eng_devcrypto.c
>  @@ -16,6 +16,7 @@
> @@ -80,7 +78,7 @@ index a2c9a966f7..5ec38ca8f3 100644
>
>       /*
>        * Code further down must make sure that only NIDs in the table above
> -@@ -333,19 +367,40 @@ static int cipher_cleanup(EVP_CIPHER_CTX *ctx)
> +@@ -333,19 +367,40 @@ static int cipher_cleanup(EVP_CIPHER_CTX
>   }
>
>   /*
> @@ -186,7 +184,7 @@ index a2c9a966f7..5ec38ca8f3 100644
>   static const EVP_CIPHER *get_cipher_method(int nid)
>   {
>       size_t i = get_cipher_data_index(nid);
> -@@ -438,6 +520,36 @@ static int devcrypto_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
> +@@ -438,6 +520,36 @@ static int devcrypto_ciphers(ENGINE *e,
>       return *cipher != NULL;
>   }
>
> @@ -247,7 +245,7 @@ index a2c9a966f7..5ec38ca8f3 100644
>
>       /*
>        * Code further down must make sure that only NIDs in the table above
> -@@ -516,8 +637,8 @@ static const struct digest_data_st *get_digest_data(int nid)
> +@@ -516,8 +637,8 @@ static const struct digest_data_st *get_
>   }
>
>   /*
> @@ -258,7 +256,7 @@ index a2c9a966f7..5ec38ca8f3 100644
>    */
>
>   static int digest_init(EVP_MD_CTX *ctx)
> -@@ -630,52 +751,94 @@ static int digest_cleanup(EVP_MD_CTX *ctx)
> +@@ -630,52 +751,94 @@ static int digest_cleanup(EVP_MD_CTX *ct
>       return clean_devcrypto_session(&digest_ctx->sess);
>   }
>
> @@ -403,7 +401,7 @@ index a2c9a966f7..5ec38ca8f3 100644
>       }
>   }
>
> -@@ -739,8 +909,154 @@ static int devcrypto_digests(ENGINE *e, const EVP_MD **digest,
> +@@ -739,7 +909,153 @@ static int devcrypto_digests(ENGINE *e,
>       return *digest != NULL;
>   }
>
> @@ -479,8 +477,8 @@ index a2c9a966f7..5ec38ca8f3 100644
>  +    "DIGESTS",
>  +    "either ALL, NONE, or a comma-separated list of digests to enable [default=ALL]",
>  +    ENGINE_CMD_FLAG_STRING},
> - #endif
> -
> ++#endif
> ++
>  +   {0, NULL, NULL, 0}
>  +};
>  +
> @@ -504,7 +502,7 @@ index a2c9a966f7..5ec38ca8f3 100644
>  +        use_softdrivers = i;
>  +#ifdef IMPLEMENT_DIGEST
>  +        rebuild_known_digest_nids(e);
> -+#endif
> + #endif
>  +        rebuild_known_cipher_nids(e);
>  +        return 1;
>  +#endif /* CIOCGSESSINFO */
> @@ -554,11 +552,10 @@ index a2c9a966f7..5ec38ca8f3 100644
>  +    }
>  +    return 0;
>  +}
> -+
> +
>   /******************************************************************************
>    *
> -  * LOAD / UNLOAD
> -@@ -793,6 +1109,8 @@ void engine_load_devcrypto_int()
> +@@ -806,6 +1122,8 @@ void engine_load_devcrypto_int()
>
>       if (!ENGINE_set_id(e, "devcrypto")
>           || !ENGINE_set_name(e, "/dev/crypto engine")
> diff --git a/package/libs/openssl/patches/420-eng_devcrypto-add-command-to-dump-driver-info.patch b/package/libs/openssl/patches/420-eng_devcrypto-add-command-to-dump-driver-info.patch
> index ad83a51a10..eee71c6c62 100644
> --- a/package/libs/openssl/patches/420-eng_devcrypto-add-command-to-dump-driver-info.patch
> +++ b/package/libs/openssl/patches/420-eng_devcrypto-add-command-to-dump-driver-info.patch
> @@ -1,4 +1,4 @@
> -From 78e7b1cc7119622645bc5a8542c55b6c95dc7868 Mon Sep 17 00:00:00 2001
> +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
>  From: Eneas U de Queiroz <cote2004-github at yahoo.com>
>  Date: Tue, 6 Nov 2018 22:54:07 -0200
>  Subject: eng_devcrypto: add command to dump driver info
> @@ -11,11 +11,9 @@ Reviewed-by: Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
>  Reviewed-by: Richard Levitte <levitte at openssl.org>
>  (Merged from https://github.com/openssl/openssl/pull/7585)
>
> -diff --git a/crypto/engine/eng_devcrypto.c b/crypto/engine/eng_devcrypto.c
> -index 5ec38ca8f3..64dc6b891d 100644
>  --- a/crypto/engine/eng_devcrypto.c
>  +++ b/crypto/engine/eng_devcrypto.c
> -@@ -50,16 +50,20 @@ static int use_softdrivers = DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS;
> +@@ -50,16 +50,20 @@ static int use_softdrivers = DEVCRYPTO_D
>    */
>   struct driver_info_st {
>       enum devcrypto_status_t {
> @@ -82,7 +80,7 @@ index 5ec38ca8f3..64dc6b891d 100644
>   #endif /* CIOCGSESSINFO */
>           }
>           ioctl(cfd, CIOCFSESSION, &sess.ses);
> -@@ -505,8 +514,11 @@ static void destroy_all_cipher_methods(void)
> +@@ -505,8 +514,11 @@ static void destroy_all_cipher_methods(v
>   {
>       size_t i;
>
> @@ -95,7 +93,7 @@ index 5ec38ca8f3..64dc6b891d 100644
>   }
>
>   static int devcrypto_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
> -@@ -550,6 +562,40 @@ static int cryptodev_select_cipher_cb(const char *str, int len, void *usr)
> +@@ -550,6 +562,40 @@ static int cryptodev_select_cipher_cb(co
>       return 1;
>   }
>
> @@ -190,7 +188,7 @@ index 5ec38ca8f3..64dc6b891d 100644
>               EVP_MD_meth_free(known_digest_methods[i]);
>               known_digest_methods[i] = NULL;
>               goto finish;
> -@@ -894,8 +945,11 @@ static void destroy_all_digest_methods(void)
> +@@ -894,8 +945,11 @@ static void destroy_all_digest_methods(v
>   {
>       size_t i;
>
> @@ -203,7 +201,7 @@ index 5ec38ca8f3..64dc6b891d 100644
>   }
>
>   static int devcrypto_digests(ENGINE *e, const EVP_MD **digest,
> -@@ -939,6 +993,43 @@ static int cryptodev_select_digest_cb(const char *str, int len, void *usr)
> +@@ -939,6 +993,43 @@ static int cryptodev_select_digest_cb(co
>       return 1;
>   }
>
> @@ -247,7 +245,7 @@ index 5ec38ca8f3..64dc6b891d 100644
>   #endif
>
>   /******************************************************************************
> -@@ -983,6 +1074,11 @@ static const ENGINE_CMD_DEFN devcrypto_cmds[] = {
> +@@ -983,6 +1074,11 @@ static const ENGINE_CMD_DEFN devcrypto_c
>       ENGINE_CMD_FLAG_STRING},
>   #endif
>
> @@ -259,7 +257,7 @@ index 5ec38ca8f3..64dc6b891d 100644
>      {0, NULL, NULL, 0}
>   };
>
> -@@ -1051,6 +1147,13 @@ static int devcrypto_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
> +@@ -1051,6 +1147,13 @@ static int devcrypto_ctrl(ENGINE *e, int
>           return 1;
>   #endif /* IMPLEMENT_DIGEST */
>
> diff --git a/package/libs/openssl/patches/430-e_devcrypto-make-the-dev-crypto-engine-dynamic.patch b/package/libs/openssl/patches/430-e_devcrypto-make-the-dev-crypto-engine-dynamic.patch
> index ea3f8fb8a7..248099d4d5 100644
> --- a/package/libs/openssl/patches/430-e_devcrypto-make-the-dev-crypto-engine-dynamic.patch
> +++ b/package/libs/openssl/patches/430-e_devcrypto-make-the-dev-crypto-engine-dynamic.patch
> @@ -8,8 +8,6 @@ engines/e_devcrypto.c.
>
>  Signed-off-by: Eneas U de Queiroz <cote2004-github at yahoo.com>
>
> -diff --git a/crypto/engine/build.info b/crypto/engine/build.info
> -index e00802a3fd..47fe948966 100644
>  --- a/crypto/engine/build.info
>  +++ b/crypto/engine/build.info
>  @@ -6,6 +6,3 @@ SOURCE[../../libcrypto]=\
> @@ -19,209 +17,2578 @@ index e00802a3fd..47fe948966 100644
>  -IF[{- !$disabled{devcryptoeng} -}]
>  -  SOURCE[../../libcrypto]=eng_devcrypto.c
>  -ENDIF
> -diff --git a/crypto/init.c b/crypto/init.c
> -index 1b0d523bea..ee3e2eb075 100644
> ---- a/crypto/init.c
> -+++ b/crypto/init.c
> -@@ -329,18 +329,6 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_engine_openssl)
> -     engine_load_openssl_int();
> -     return 1;
> - }
> --# ifndef OPENSSL_NO_DEVCRYPTOENG
> --static CRYPTO_ONCE engine_devcrypto = CRYPTO_ONCE_STATIC_INIT;
> --DEFINE_RUN_ONCE_STATIC(ossl_init_engine_devcrypto)
> +--- a/crypto/engine/eng_devcrypto.c
> ++++ /dev/null
> +@@ -1,1277 +0,0 @@
> +-/*
> +- * Copyright 2017-2021 The OpenSSL Project Authors. All Rights Reserved.
> +- *
> +- * Licensed under the OpenSSL license (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
> +- */
> +-
> +-#include "e_os.h"
> +-#include <string.h>
> +-#include <sys/types.h>
> +-#include <sys/stat.h>
> +-#include <fcntl.h>
> +-#include <sys/ioctl.h>
> +-#include <unistd.h>
> +-#include <assert.h>
> +-
> +-#include <openssl/conf.h>
> +-#include <openssl/evp.h>
> +-#include <openssl/err.h>
> +-#include <openssl/engine.h>
> +-#include <openssl/objects.h>
> +-#include <crypto/cryptodev.h>
> +-
> +-#include "crypto/engine.h"
> +-
> +-/* #define ENGINE_DEVCRYPTO_DEBUG */
> +-
> +-#if CRYPTO_ALGORITHM_MIN < CRYPTO_ALGORITHM_MAX
> +-# define CHECK_BSD_STYLE_MACROS
> +-#endif
> +-
> +-/*
> +- * ONE global file descriptor for all sessions.  This allows operations
> +- * such as digest session data copying (see digest_copy()), but is also
> +- * saner...  why re-open /dev/crypto for every session?
> +- */
> +-static int cfd;
> +-#define DEVCRYPTO_REQUIRE_ACCELERATED 0 /* require confirmation of acceleration */
> +-#define DEVCRYPTO_USE_SOFTWARE        1 /* allow software drivers */
> +-#define DEVCRYPTO_REJECT_SOFTWARE     2 /* only disallow confirmed software drivers */
> +-
> +-#define DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS DEVCRYPTO_REJECT_SOFTWARE
> +-static int use_softdrivers = DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS;
> +-
> +-/*
> +- * cipher/digest status & acceleration definitions
> +- * Make sure the defaults are set to 0
> +- */
> +-struct driver_info_st {
> +-    enum devcrypto_status_t {
> +-        DEVCRYPTO_STATUS_FAILURE         = -3, /* unusable for other reason */
> +-        DEVCRYPTO_STATUS_NO_CIOCCPHASH   = -2, /* hash state copy not supported */
> +-        DEVCRYPTO_STATUS_NO_CIOCGSESSION = -1, /* session open failed */
> +-        DEVCRYPTO_STATUS_UNKNOWN         =  0, /* not tested yet */
> +-        DEVCRYPTO_STATUS_USABLE          =  1  /* algo can be used */
> +-    } status;
> +-
> +-    enum devcrypto_accelerated_t {
> +-        DEVCRYPTO_NOT_ACCELERATED        = -1, /* software implemented */
> +-        DEVCRYPTO_ACCELERATION_UNKNOWN   =  0, /* acceleration support unkown */
> +-        DEVCRYPTO_ACCELERATED            =  1  /* hardware accelerated */
> +-    } accelerated;
> +-
> +-    char *driver_name;
> +-};
> +-
> +-static int clean_devcrypto_session(struct session_op *sess) {
> +-    if (ioctl(cfd, CIOCFSESSION, &sess->ses) < 0) {
> +-        SYSerr(SYS_F_IOCTL, errno);
> +-        return 0;
> +-    }
> +-    memset(sess, 0, sizeof(struct session_op));
> +-    return 1;
> +-}
> +-
> +-/******************************************************************************
> +- *
> +- * Ciphers
> +- *
> +- * Because they all do the same basic operation, we have only one set of
> +- * method functions for them all to share, and a mapping table between
> +- * NIDs and cryptodev IDs, with all the necessary size data.
> +- *
> +- *****/
> +-
> +-struct cipher_ctx {
> +-    struct session_op sess;
> +-    int op;                      /* COP_ENCRYPT or COP_DECRYPT */
> +-    unsigned long mode;          /* EVP_CIPH_*_MODE */
> +-
> +-    /* to handle ctr mode being a stream cipher */
> +-    unsigned char partial[EVP_MAX_BLOCK_LENGTH];
> +-    unsigned int blocksize, num;
> +-};
> +-
> +-static const struct cipher_data_st {
> +-    int nid;
> +-    int blocksize;
> +-    int keylen;
> +-    int ivlen;
> +-    int flags;
> +-    int devcryptoid;
> +-} cipher_data[] = {
> +-#ifndef OPENSSL_NO_DES
> +-    { NID_des_cbc, 8, 8, 8, EVP_CIPH_CBC_MODE, CRYPTO_DES_CBC },
> +-    { NID_des_ede3_cbc, 8, 24, 8, EVP_CIPH_CBC_MODE, CRYPTO_3DES_CBC },
> +-#endif
> +-#ifndef OPENSSL_NO_BF
> +-    { NID_bf_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_BLF_CBC },
> +-#endif
> +-#ifndef OPENSSL_NO_CAST
> +-    { NID_cast5_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_CAST_CBC },
> +-#endif
> +-    { NID_aes_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
> +-    { NID_aes_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
> +-    { NID_aes_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
> +-#ifndef OPENSSL_NO_RC4
> +-    { NID_rc4, 1, 16, 0, EVP_CIPH_STREAM_CIPHER, CRYPTO_ARC4 },
> +-#endif
> +-#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_CTR)
> +-    { NID_aes_128_ctr, 16, 128 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
> +-    { NID_aes_192_ctr, 16, 192 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
> +-    { NID_aes_256_ctr, 16, 256 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
> +-#endif
> +-#if 0                            /* Not yet supported */
> +-    { NID_aes_128_xts, 16, 128 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS },
> +-    { NID_aes_256_xts, 16, 256 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS },
> +-#endif
> +-#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_ECB)
> +-    { NID_aes_128_ecb, 16, 128 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
> +-    { NID_aes_192_ecb, 16, 192 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
> +-    { NID_aes_256_ecb, 16, 256 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
> +-#endif
> +-#if 0                            /* Not yet supported */
> +-    { NID_aes_128_gcm, 16, 128 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
> +-    { NID_aes_192_gcm, 16, 192 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
> +-    { NID_aes_256_gcm, 16, 256 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
> +-#endif
> +-#ifndef OPENSSL_NO_CAMELLIA
> +-    { NID_camellia_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE,
> +-      CRYPTO_CAMELLIA_CBC },
> +-    { NID_camellia_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE,
> +-      CRYPTO_CAMELLIA_CBC },
> +-    { NID_camellia_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE,
> +-      CRYPTO_CAMELLIA_CBC },
> +-#endif
> +-};
> +-
> +-static size_t find_cipher_data_index(int nid)
>  -{
> --#  ifdef OPENSSL_INIT_DEBUG
> --    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_devcrypto: "
> --                    "engine_load_devcrypto_int()\n");
> --#  endif
> --    engine_load_devcrypto_int();
> +-    size_t i;
> +-
> +-    for (i = 0; i < OSSL_NELEM(cipher_data); i++)
> +-        if (nid == cipher_data[i].nid)
> +-            return i;
> +-    return (size_t)-1;
> +-}
> +-
> +-static size_t get_cipher_data_index(int nid)
> +-{
> +-    size_t i = find_cipher_data_index(nid);
> +-
> +-    if (i != (size_t)-1)
> +-        return i;
> +-
> +-    /*
> +-     * Code further down must make sure that only NIDs in the table above
> +-     * are used.  If any other NID reaches this function, there's a grave
> +-     * coding error further down.
> +-     */
> +-    assert("Code that never should be reached" == NULL);
> +-    return -1;
> +-}
> +-
> +-static const struct cipher_data_st *get_cipher_data(int nid)
> +-{
> +-    return &cipher_data[get_cipher_data_index(nid)];
> +-}
> +-
> +-/*
> +- * Following are the three necessary functions to map OpenSSL functionality
> +- * with cryptodev.
> +- */
> +-
> +-static int cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
> +-                       const unsigned char *iv, int enc)
> +-{
> +-    struct cipher_ctx *cipher_ctx =
> +-        (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
> +-    const struct cipher_data_st *cipher_d =
> +-        get_cipher_data(EVP_CIPHER_CTX_nid(ctx));
> +-
> +-    /* cleanup a previous session */
> +-    if (cipher_ctx->sess.ses != 0 &&
> +-        clean_devcrypto_session(&cipher_ctx->sess) == 0)
> +-        return 0;
> +-
> +-    cipher_ctx->sess.cipher = cipher_d->devcryptoid;
> +-    cipher_ctx->sess.keylen = cipher_d->keylen;
> +-    cipher_ctx->sess.key = (void *)key;
> +-    cipher_ctx->op = enc ? COP_ENCRYPT : COP_DECRYPT;
> +-    cipher_ctx->mode = cipher_d->flags & EVP_CIPH_MODE;
> +-    cipher_ctx->blocksize = cipher_d->blocksize;
> +-    if (ioctl(cfd, CIOCGSESSION, &cipher_ctx->sess) < 0) {
> +-        SYSerr(SYS_F_IOCTL, errno);
> +-        return 0;
> +-    }
> +-
> +-    return 1;
> +-}
> +-
> +-static int cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
> +-                            const unsigned char *in, size_t inl)
> +-{
> +-    struct cipher_ctx *cipher_ctx =
> +-        (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
> +-    struct crypt_op cryp;
> +-    unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx);
> +-#if !defined(COP_FLAG_WRITE_IV)
> +-    unsigned char saved_iv[EVP_MAX_IV_LENGTH];
> +-    const unsigned char *ivptr;
> +-    size_t nblocks, ivlen;
> +-#endif
> +-
> +-    memset(&cryp, 0, sizeof(cryp));
> +-    cryp.ses = cipher_ctx->sess.ses;
> +-    cryp.len = inl;
> +-    cryp.src = (void *)in;
> +-    cryp.dst = (void *)out;
> +-    cryp.iv = (void *)iv;
> +-    cryp.op = cipher_ctx->op;
> +-#if !defined(COP_FLAG_WRITE_IV)
> +-    cryp.flags = 0;
> +-
> +-    ivlen = EVP_CIPHER_CTX_iv_length(ctx);
> +-    if (ivlen > 0)
> +-        switch (cipher_ctx->mode) {
> +-        case EVP_CIPH_CBC_MODE:
> +-            assert(inl >= ivlen);
> +-            if (!EVP_CIPHER_CTX_encrypting(ctx)) {
> +-                ivptr = in + inl - ivlen;
> +-                memcpy(saved_iv, ivptr, ivlen);
> +-            }
> +-            break;
> +-
> +-        case EVP_CIPH_CTR_MODE:
> +-            break;
> +-
> +-        default: /* should not happen */
> +-            return 0;
> +-        }
> +-#else
> +-    cryp.flags = COP_FLAG_WRITE_IV;
> +-#endif
> +-
> +-    if (ioctl(cfd, CIOCCRYPT, &cryp) < 0) {
> +-        SYSerr(SYS_F_IOCTL, errno);
> +-        return 0;
> +-    }
> +-
> +-#if !defined(COP_FLAG_WRITE_IV)
> +-    if (ivlen > 0)
> +-        switch (cipher_ctx->mode) {
> +-        case EVP_CIPH_CBC_MODE:
> +-            assert(inl >= ivlen);
> +-            if (EVP_CIPHER_CTX_encrypting(ctx))
> +-                ivptr = out + inl - ivlen;
> +-            else
> +-                ivptr = saved_iv;
> +-
> +-            memcpy(iv, ivptr, ivlen);
> +-            break;
> +-
> +-        case EVP_CIPH_CTR_MODE:
> +-            nblocks = (inl + cipher_ctx->blocksize - 1)
> +-                      / cipher_ctx->blocksize;
> +-            do {
> +-                ivlen--;
> +-                nblocks += iv[ivlen];
> +-                iv[ivlen] = (uint8_t) nblocks;
> +-                nblocks >>= 8;
> +-            } while (ivlen);
> +-            break;
> +-
> +-        default: /* should not happen */
> +-            return 0;
> +-        }
> +-#endif
> +-
> +-    return 1;
> +-}
> +-
> +-static int ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
> +-                         const unsigned char *in, size_t inl)
> +-{
> +-    struct cipher_ctx *cipher_ctx =
> +-        (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
> +-    size_t nblocks, len;
> +-
> +-    /* initial partial block */
> +-    while (cipher_ctx->num && inl) {
> +-        (*out++) = *(in++) ^ cipher_ctx->partial[cipher_ctx->num];
> +-        --inl;
> +-        cipher_ctx->num = (cipher_ctx->num + 1) % cipher_ctx->blocksize;
> +-    }
> +-
> +-    /* full blocks */
> +-    if (inl > (unsigned int) cipher_ctx->blocksize) {
> +-        nblocks = inl/cipher_ctx->blocksize;
> +-        len = nblocks * cipher_ctx->blocksize;
> +-        if (cipher_do_cipher(ctx, out, in, len) < 1)
> +-            return 0;
> +-        inl -= len;
> +-        out += len;
> +-        in += len;
> +-    }
> +-
> +-    /* final partial block */
> +-    if (inl) {
> +-        memset(cipher_ctx->partial, 0, cipher_ctx->blocksize);
> +-        if (cipher_do_cipher(ctx, cipher_ctx->partial, cipher_ctx->partial,
> +-            cipher_ctx->blocksize) < 1)
> +-            return 0;
> +-        while (inl--) {
> +-            out[cipher_ctx->num] = in[cipher_ctx->num]
> +-                                   ^ cipher_ctx->partial[cipher_ctx->num];
> +-            cipher_ctx->num++;
> +-        }
> +-    }
> +-
> +-    return 1;
> +-}
> +-
> +-static int cipher_ctrl(EVP_CIPHER_CTX *ctx, int type, int p1, void* p2)
> +-{
> +-    struct cipher_ctx *cipher_ctx =
> +-        (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
> +-    EVP_CIPHER_CTX *to_ctx = (EVP_CIPHER_CTX *)p2;
> +-    struct cipher_ctx *to_cipher_ctx;
> +-
> +-    switch (type) {
> +-    case EVP_CTRL_COPY:
> +-        if (cipher_ctx == NULL)
> +-            return 1;
> +-        /* when copying the context, a new session needs to be initialized */
> +-        to_cipher_ctx =
> +-            (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(to_ctx);
> +-        memset(&to_cipher_ctx->sess, 0, sizeof(to_cipher_ctx->sess));
> +-        return cipher_init(to_ctx, cipher_ctx->sess.key, EVP_CIPHER_CTX_iv(ctx),
> +-                           (cipher_ctx->op == COP_ENCRYPT));
> +-
> +-    case EVP_CTRL_INIT:
> +-        memset(&cipher_ctx->sess, 0, sizeof(cipher_ctx->sess));
> +-        return 1;
> +-
> +-    default:
> +-        break;
> +-    }
> +-
> +-    return -1;
> +-}
> +-
> +-static int cipher_cleanup(EVP_CIPHER_CTX *ctx)
> +-{
> +-    struct cipher_ctx *cipher_ctx =
> +-        (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
> +-
> +-    return clean_devcrypto_session(&cipher_ctx->sess);
> +-}
> +-
> +-/*
> +- * Keep tables of known nids, associated methods, selected ciphers, and driver
> +- * info.
> +- * Note that known_cipher_nids[] isn't necessarily indexed the same way as
> +- * cipher_data[] above, which the other tables are.
> +- */
> +-static int known_cipher_nids[OSSL_NELEM(cipher_data)];
> +-static int known_cipher_nids_amount = -1; /* -1 indicates not yet initialised */
> +-static EVP_CIPHER *known_cipher_methods[OSSL_NELEM(cipher_data)] = { NULL, };
> +-static int selected_ciphers[OSSL_NELEM(cipher_data)];
> +-static struct driver_info_st cipher_driver_info[OSSL_NELEM(cipher_data)];
> +-
> +-
> +-static int devcrypto_test_cipher(size_t cipher_data_index)
> +-{
> +-    return (cipher_driver_info[cipher_data_index].status == DEVCRYPTO_STATUS_USABLE
> +-            && selected_ciphers[cipher_data_index] == 1
> +-            && (cipher_driver_info[cipher_data_index].accelerated
> +-                    == DEVCRYPTO_ACCELERATED
> +-                || use_softdrivers == DEVCRYPTO_USE_SOFTWARE
> +-                || (cipher_driver_info[cipher_data_index].accelerated
> +-                        != DEVCRYPTO_NOT_ACCELERATED
> +-                    && use_softdrivers == DEVCRYPTO_REJECT_SOFTWARE)));
> +-}
> +-
> +-static void prepare_cipher_methods(void)
> +-{
> +-    size_t i;
> +-    struct session_op sess;
> +-    unsigned long cipher_mode;
> +-#ifdef CIOCGSESSINFO
> +-    struct session_info_op siop;
> +-#endif
> +-
> +-    memset(&cipher_driver_info, 0, sizeof(cipher_driver_info));
> +-
> +-    memset(&sess, 0, sizeof(sess));
> +-    sess.key = (void *)"01234567890123456789012345678901234567890123456789";
> +-
> +-    for (i = 0, known_cipher_nids_amount = 0;
> +-         i < OSSL_NELEM(cipher_data); i++) {
> +-
> +-        selected_ciphers[i] = 1;
> +-        /*
> +-         * Check that the cipher is usable
> +-         */
> +-        sess.cipher = cipher_data[i].devcryptoid;
> +-        sess.keylen = cipher_data[i].keylen;
> +-        if (ioctl(cfd, CIOCGSESSION, &sess) < 0) {
> +-            cipher_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;
> +-            continue;
> +-        }
> +-
> +-        cipher_mode = cipher_data[i].flags & EVP_CIPH_MODE;
> +-
> +-        if ((known_cipher_methods[i] =
> +-                 EVP_CIPHER_meth_new(cipher_data[i].nid,
> +-                                     cipher_mode == EVP_CIPH_CTR_MODE ? 1 :
> +-                                                    cipher_data[i].blocksize,
> +-                                     cipher_data[i].keylen)) == NULL
> +-            || !EVP_CIPHER_meth_set_iv_length(known_cipher_methods[i],
> +-                                              cipher_data[i].ivlen)
> +-            || !EVP_CIPHER_meth_set_flags(known_cipher_methods[i],
> +-                                          cipher_data[i].flags
> +-                                          | EVP_CIPH_CUSTOM_COPY
> +-                                          | EVP_CIPH_CTRL_INIT
> +-                                          | EVP_CIPH_FLAG_DEFAULT_ASN1)
> +-            || !EVP_CIPHER_meth_set_init(known_cipher_methods[i], cipher_init)
> +-            || !EVP_CIPHER_meth_set_do_cipher(known_cipher_methods[i],
> +-                                     cipher_mode == EVP_CIPH_CTR_MODE ?
> +-                                              ctr_do_cipher :
> +-                                              cipher_do_cipher)
> +-            || !EVP_CIPHER_meth_set_ctrl(known_cipher_methods[i], cipher_ctrl)
> +-            || !EVP_CIPHER_meth_set_cleanup(known_cipher_methods[i],
> +-                                            cipher_cleanup)
> +-            || !EVP_CIPHER_meth_set_impl_ctx_size(known_cipher_methods[i],
> +-                                                  sizeof(struct cipher_ctx))) {
> +-            cipher_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
> +-            EVP_CIPHER_meth_free(known_cipher_methods[i]);
> +-            known_cipher_methods[i] = NULL;
> +-        } else {
> +-            cipher_driver_info[i].status = DEVCRYPTO_STATUS_USABLE;
> +-#ifdef CIOCGSESSINFO
> +-            siop.ses = sess.ses;
> +-            if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0) {
> +-                cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;
> +-            } else {
> +-                cipher_driver_info[i].driver_name =
> +-                    OPENSSL_strndup(siop.cipher_info.cra_driver_name,
> +-                                    CRYPTODEV_MAX_ALG_NAME);
> +-                if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY))
> +-                    cipher_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;
> +-                else
> +-                    cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;
> +-            }
> +-#endif /* CIOCGSESSINFO */
> +-        }
> +-        ioctl(cfd, CIOCFSESSION, &sess.ses);
> +-        if (devcrypto_test_cipher(i)) {
> +-            known_cipher_nids[known_cipher_nids_amount++] =
> +-                cipher_data[i].nid;
> +-        }
> +-    }
> +-}
> +-
> +-static void rebuild_known_cipher_nids(ENGINE *e)
> +-{
> +-    size_t i;
> +-
> +-    for (i = 0, known_cipher_nids_amount = 0; i < OSSL_NELEM(cipher_data); i++) {
> +-        if (devcrypto_test_cipher(i))
> +-            known_cipher_nids[known_cipher_nids_amount++] = cipher_data[i].nid;
> +-    }
> +-    ENGINE_unregister_ciphers(e);
> +-    ENGINE_register_ciphers(e);
> +-}
> +-
> +-static const EVP_CIPHER *get_cipher_method(int nid)
> +-{
> +-    size_t i = get_cipher_data_index(nid);
> +-
> +-    if (i == (size_t)-1)
> +-        return NULL;
> +-    return known_cipher_methods[i];
> +-}
> +-
> +-static int get_cipher_nids(const int **nids)
> +-{
> +-    *nids = known_cipher_nids;
> +-    return known_cipher_nids_amount;
> +-}
> +-
> +-static void destroy_cipher_method(int nid)
> +-{
> +-    size_t i = get_cipher_data_index(nid);
> +-
> +-    EVP_CIPHER_meth_free(known_cipher_methods[i]);
> +-    known_cipher_methods[i] = NULL;
> +-}
> +-
> +-static void destroy_all_cipher_methods(void)
> +-{
> +-    size_t i;
> +-
> +-    for (i = 0; i < OSSL_NELEM(cipher_data); i++) {
> +-        destroy_cipher_method(cipher_data[i].nid);
> +-        OPENSSL_free(cipher_driver_info[i].driver_name);
> +-        cipher_driver_info[i].driver_name = NULL;
> +-    }
> +-}
> +-
> +-static int devcrypto_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
> +-                             const int **nids, int nid)
> +-{
> +-    if (cipher == NULL)
> +-        return get_cipher_nids(nids);
> +-
> +-    *cipher = get_cipher_method(nid);
> +-
> +-    return *cipher != NULL;
> +-}
> +-
> +-static void devcrypto_select_all_ciphers(int *cipher_list)
> +-{
> +-    size_t i;
> +-
> +-    for (i = 0; i < OSSL_NELEM(cipher_data); i++)
> +-        cipher_list[i] = 1;
> +-}
> +-
> +-static int cryptodev_select_cipher_cb(const char *str, int len, void *usr)
> +-{
> +-    int *cipher_list = (int *)usr;
> +-    char *name;
> +-    const EVP_CIPHER *EVP;
> +-    size_t i;
> +-
> +-    if (len == 0)
> +-        return 1;
> +-    if (usr == NULL || (name = OPENSSL_strndup(str, len)) == NULL)
> +-        return 0;
> +-    EVP = EVP_get_cipherbyname(name);
> +-    if (EVP == NULL)
> +-        fprintf(stderr, "devcrypto: unknown cipher %s\n", name);
> +-    else if ((i = find_cipher_data_index(EVP_CIPHER_nid(EVP))) != (size_t)-1)
> +-        cipher_list[i] = 1;
> +-    else
> +-        fprintf(stderr, "devcrypto: cipher %s not available\n", name);
> +-    OPENSSL_free(name);
>  -    return 1;
>  -}
> +-
> +-static void dump_cipher_info(void)
> +-{
> +-    size_t i;
> +-    const char *name;
> +-
> +-    fprintf (stderr, "Information about ciphers supported by the /dev/crypto"
> +-             " engine:\n");
> +-#ifndef CIOCGSESSINFO
> +-    fprintf(stderr, "CIOCGSESSINFO (session info call) unavailable\n");
> +-#endif
> +-    for (i = 0; i < OSSL_NELEM(cipher_data); i++) {
> +-        name = OBJ_nid2sn(cipher_data[i].nid);
> +-        fprintf (stderr, "Cipher %s, NID=%d, /dev/crypto info: id=%d, ",
> +-                 name ? name : "unknown", cipher_data[i].nid,
> +-                 cipher_data[i].devcryptoid);
> +-        if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCGSESSION ) {
> +-            fprintf (stderr, "CIOCGSESSION (session open call) failed\n");
> +-            continue;
> +-        }
> +-        fprintf (stderr, "driver=%s ", cipher_driver_info[i].driver_name ?
> +-                 cipher_driver_info[i].driver_name : "unknown");
> +-        if (cipher_driver_info[i].accelerated == DEVCRYPTO_ACCELERATED)
> +-            fprintf(stderr, "(hw accelerated)");
> +-        else if (cipher_driver_info[i].accelerated == DEVCRYPTO_NOT_ACCELERATED)
> +-            fprintf(stderr, "(software)");
> +-        else
> +-            fprintf(stderr, "(acceleration status unknown)");
> +-        if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_FAILURE)
> +-            fprintf (stderr, ". Cipher setup failed");
> +-        fprintf(stderr, "\n");
> +-    }
> +-    fprintf(stderr, "\n");
> +-}
> +-
> +-/*
> +- * We only support digests if the cryptodev implementation supports multiple
> +- * data updates and session copying.  Otherwise, we would be forced to maintain
> +- * a cache, which is perilous if there's a lot of data coming in (if someone
> +- * wants to checksum an OpenSSL tarball, for example).
> +- */
> +-#if defined(CIOCCPHASH) && defined(COP_FLAG_UPDATE) && defined(COP_FLAG_FINAL)
> +-#define IMPLEMENT_DIGEST
> +-
> +-/******************************************************************************
> +- *
> +- * Digests
> +- *
> +- * Because they all do the same basic operation, we have only one set of
> +- * method functions for them all to share, and a mapping table between
> +- * NIDs and cryptodev IDs, with all the necessary size data.
> +- *
> +- *****/
> +-
> +-struct digest_ctx {
> +-    struct session_op sess;
> +-    /* This signals that the init function was called, not that it succeeded. */
> +-    int init_called;
> +-    unsigned char digest_res[HASH_MAX_LEN];
> +-};
> +-
> +-static const struct digest_data_st {
> +-    int nid;
> +-    int blocksize;
> +-    int digestlen;
> +-    int devcryptoid;
> +-} digest_data[] = {
> +-#ifndef OPENSSL_NO_MD5
> +-    { NID_md5, /* MD5_CBLOCK */ 64, 16, CRYPTO_MD5 },
> +-#endif
> +-    { NID_sha1, SHA_CBLOCK, 20, CRYPTO_SHA1 },
> +-#ifndef OPENSSL_NO_RMD160
> +-# if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_RIPEMD160)
> +-    { NID_ripemd160, /* RIPEMD160_CBLOCK */ 64, 20, CRYPTO_RIPEMD160 },
>  -# endif
> -
> - # ifndef OPENSSL_NO_RDRAND
> - static CRYPTO_ONCE engine_rdrand = CRYPTO_ONCE_STATIC_INIT;
> -@@ -365,6 +353,18 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_engine_dynamic)
> -     return 1;
> - }
> - # ifndef OPENSSL_NO_STATIC_ENGINE
> -+#  ifndef OPENSSL_NO_DEVCRYPTOENG
> -+static CRYPTO_ONCE engine_devcrypto = CRYPTO_ONCE_STATIC_INIT;
> -+DEFINE_RUN_ONCE_STATIC(ossl_init_engine_devcrypto)
> +-#endif
> +-#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_224)
> +-    { NID_sha224, SHA256_CBLOCK, 224 / 8, CRYPTO_SHA2_224 },
> +-#endif
> +-#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_256)
> +-    { NID_sha256, SHA256_CBLOCK, 256 / 8, CRYPTO_SHA2_256 },
> +-#endif
> +-#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_384)
> +-    { NID_sha384, SHA512_CBLOCK, 384 / 8, CRYPTO_SHA2_384 },
> +-#endif
> +-#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_512)
> +-    { NID_sha512, SHA512_CBLOCK, 512 / 8, CRYPTO_SHA2_512 },
> +-#endif
> +-};
> +-
> +-static size_t find_digest_data_index(int nid)
> +-{
> +-    size_t i;
> +-
> +-    for (i = 0; i < OSSL_NELEM(digest_data); i++)
> +-        if (nid == digest_data[i].nid)
> +-            return i;
> +-    return (size_t)-1;
> +-}
> +-
> +-static size_t get_digest_data_index(int nid)
> +-{
> +-    size_t i = find_digest_data_index(nid);
> +-
> +-    if (i != (size_t)-1)
> +-        return i;
> +-
> +-    /*
> +-     * Code further down must make sure that only NIDs in the table above
> +-     * are used.  If any other NID reaches this function, there's a grave
> +-     * coding error further down.
> +-     */
> +-    assert("Code that never should be reached" == NULL);
> +-    return -1;
> +-}
> +-
> +-static const struct digest_data_st *get_digest_data(int nid)
> +-{
> +-    return &digest_data[get_digest_data_index(nid)];
> +-}
> +-
> +-/*
> +- * Following are the five necessary functions to map OpenSSL functionality
> +- * with cryptodev: init, update, final, cleanup, and copy.
> +- */
> +-
> +-static int digest_init(EVP_MD_CTX *ctx)
> +-{
> +-    struct digest_ctx *digest_ctx =
> +-        (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
> +-    const struct digest_data_st *digest_d =
> +-        get_digest_data(EVP_MD_CTX_type(ctx));
> +-
> +-    digest_ctx->init_called = 1;
> +-
> +-    memset(&digest_ctx->sess, 0, sizeof(digest_ctx->sess));
> +-    digest_ctx->sess.mac = digest_d->devcryptoid;
> +-    if (ioctl(cfd, CIOCGSESSION, &digest_ctx->sess) < 0) {
> +-        SYSerr(SYS_F_IOCTL, errno);
> +-        return 0;
> +-    }
> +-
> +-    return 1;
> +-}
> +-
> +-static int digest_op(struct digest_ctx *ctx, const void *src, size_t srclen,
> +-                     void *res, unsigned int flags)
> +-{
> +-    struct crypt_op cryp;
> +-
> +-    memset(&cryp, 0, sizeof(cryp));
> +-    cryp.ses = ctx->sess.ses;
> +-    cryp.len = srclen;
> +-    cryp.src = (void *)src;
> +-    cryp.dst = NULL;
> +-    cryp.mac = res;
> +-    cryp.flags = flags;
> +-    return ioctl(cfd, CIOCCRYPT, &cryp);
> +-}
> +-
> +-static int digest_update(EVP_MD_CTX *ctx, const void *data, size_t count)
> +-{
> +-    struct digest_ctx *digest_ctx =
> +-        (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
> +-
> +-    if (count == 0)
> +-        return 1;
> +-
> +-    if (digest_ctx == NULL)
> +-        return 0;
> +-
> +-    if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {
> +-        if (digest_op(digest_ctx, data, count, digest_ctx->digest_res, 0) >= 0)
> +-            return 1;
> +-    } else if (digest_op(digest_ctx, data, count, NULL, COP_FLAG_UPDATE) >= 0) {
> +-        return 1;
> +-    }
> +-
> +-    SYSerr(SYS_F_IOCTL, errno);
> +-    return 0;
> +-}
> +-
> +-static int digest_final(EVP_MD_CTX *ctx, unsigned char *md)
> +-{
> +-    struct digest_ctx *digest_ctx =
> +-        (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
> +-
> +-    if (md == NULL || digest_ctx == NULL)
> +-        return 0;
> +-
> +-    if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {
> +-        memcpy(md, digest_ctx->digest_res, EVP_MD_CTX_size(ctx));
> +-    } else if (digest_op(digest_ctx, NULL, 0, md, COP_FLAG_FINAL) < 0) {
> +-        SYSerr(SYS_F_IOCTL, errno);
> +-        return 0;
> +-    }
> +-
> +-    return 1;
> +-}
> +-
> +-static int digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
> +-{
> +-    struct digest_ctx *digest_from =
> +-        (struct digest_ctx *)EVP_MD_CTX_md_data(from);
> +-    struct digest_ctx *digest_to =
> +-        (struct digest_ctx *)EVP_MD_CTX_md_data(to);
> +-    struct cphash_op cphash;
> +-
> +-    if (digest_from == NULL || digest_from->init_called != 1)
> +-        return 1;
> +-
> +-    if (!digest_init(to)) {
> +-        SYSerr(SYS_F_IOCTL, errno);
> +-        return 0;
> +-    }
> +-
> +-    cphash.src_ses = digest_from->sess.ses;
> +-    cphash.dst_ses = digest_to->sess.ses;
> +-    if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) {
> +-        SYSerr(SYS_F_IOCTL, errno);
> +-        return 0;
> +-    }
> +-    return 1;
> +-}
> +-
> +-static int digest_cleanup(EVP_MD_CTX *ctx)
> +-{
> +-    struct digest_ctx *digest_ctx =
> +-        (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
> +-
> +-    if (digest_ctx == NULL)
> +-        return 1;
> +-
> +-    return clean_devcrypto_session(&digest_ctx->sess);
> +-}
> +-
> +-/*
> +- * Keep tables of known nids, associated methods, selected digests, and
> +- * driver info.
> +- * Note that known_digest_nids[] isn't necessarily indexed the same way as
> +- * digest_data[] above, which the other tables are.
> +- */
> +-static int known_digest_nids[OSSL_NELEM(digest_data)];
> +-static int known_digest_nids_amount = -1; /* -1 indicates not yet initialised */
> +-static EVP_MD *known_digest_methods[OSSL_NELEM(digest_data)] = { NULL, };
> +-static int selected_digests[OSSL_NELEM(digest_data)];
> +-static struct driver_info_st digest_driver_info[OSSL_NELEM(digest_data)];
> +-
> +-static int devcrypto_test_digest(size_t digest_data_index)
> +-{
> +-    return (digest_driver_info[digest_data_index].status == DEVCRYPTO_STATUS_USABLE
> +-            && selected_digests[digest_data_index] == 1
> +-            && (digest_driver_info[digest_data_index].accelerated
> +-                    == DEVCRYPTO_ACCELERATED
> +-                || use_softdrivers == DEVCRYPTO_USE_SOFTWARE
> +-                || (digest_driver_info[digest_data_index].accelerated
> +-                        != DEVCRYPTO_NOT_ACCELERATED
> +-                    && use_softdrivers == DEVCRYPTO_REJECT_SOFTWARE)));
> +-}
> +-
> +-static void rebuild_known_digest_nids(ENGINE *e)
> +-{
> +-    size_t i;
> +-
> +-    for (i = 0, known_digest_nids_amount = 0; i < OSSL_NELEM(digest_data); i++) {
> +-        if (devcrypto_test_digest(i))
> +-            known_digest_nids[known_digest_nids_amount++] = digest_data[i].nid;
> +-    }
> +-    ENGINE_unregister_digests(e);
> +-    ENGINE_register_digests(e);
> +-}
> +-
> +-static void prepare_digest_methods(void)
> +-{
> +-    size_t i;
> +-    struct session_op sess1, sess2;
> +-#ifdef CIOCGSESSINFO
> +-    struct session_info_op siop;
> +-#endif
> +-    struct cphash_op cphash;
> +-
> +-    memset(&digest_driver_info, 0, sizeof(digest_driver_info));
> +-
> +-    memset(&sess1, 0, sizeof(sess1));
> +-    memset(&sess2, 0, sizeof(sess2));
> +-
> +-    for (i = 0, known_digest_nids_amount = 0; i < OSSL_NELEM(digest_data);
> +-         i++) {
> +-
> +-        selected_digests[i] = 1;
> +-
> +-        /*
> +-         * Check that the digest is usable
> +-         */
> +-        sess1.mac = digest_data[i].devcryptoid;
> +-        sess2.ses = 0;
> +-        if (ioctl(cfd, CIOCGSESSION, &sess1) < 0) {
> +-            digest_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;
> +-            goto finish;
> +-        }
> +-
> +-#ifdef CIOCGSESSINFO
> +-        /* gather hardware acceleration info from the driver */
> +-        siop.ses = sess1.ses;
> +-        if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0) {
> +-            digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;
> +-        } else {
> +-            digest_driver_info[i].driver_name =
> +-                OPENSSL_strndup(siop.hash_info.cra_driver_name,
> +-                                CRYPTODEV_MAX_ALG_NAME);
> +-            if (siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)
> +-                digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;
> +-            else
> +-                digest_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;
> +-        }
> +-#endif
> +-
> +-        /* digest must be capable of hash state copy */
> +-        sess2.mac = sess1.mac;
> +-        if (ioctl(cfd, CIOCGSESSION, &sess2) < 0) {
> +-            digest_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
> +-            goto finish;
> +-        }
> +-        cphash.src_ses = sess1.ses;
> +-        cphash.dst_ses = sess2.ses;
> +-        if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) {
> +-            digest_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCCPHASH;
> +-            goto finish;
> +-        }
> +-        if ((known_digest_methods[i] = EVP_MD_meth_new(digest_data[i].nid,
> +-                                                       NID_undef)) == NULL
> +-            || !EVP_MD_meth_set_input_blocksize(known_digest_methods[i],
> +-                                                digest_data[i].blocksize)
> +-            || !EVP_MD_meth_set_result_size(known_digest_methods[i],
> +-                                            digest_data[i].digestlen)
> +-            || !EVP_MD_meth_set_init(known_digest_methods[i], digest_init)
> +-            || !EVP_MD_meth_set_update(known_digest_methods[i], digest_update)
> +-            || !EVP_MD_meth_set_final(known_digest_methods[i], digest_final)
> +-            || !EVP_MD_meth_set_copy(known_digest_methods[i], digest_copy)
> +-            || !EVP_MD_meth_set_cleanup(known_digest_methods[i], digest_cleanup)
> +-            || !EVP_MD_meth_set_app_datasize(known_digest_methods[i],
> +-                                             sizeof(struct digest_ctx))) {
> +-            digest_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
> +-            EVP_MD_meth_free(known_digest_methods[i]);
> +-            known_digest_methods[i] = NULL;
> +-            goto finish;
> +-        }
> +-        digest_driver_info[i].status = DEVCRYPTO_STATUS_USABLE;
> +-finish:
> +-        ioctl(cfd, CIOCFSESSION, &sess1.ses);
> +-        if (sess2.ses != 0)
> +-            ioctl(cfd, CIOCFSESSION, &sess2.ses);
> +-        if (devcrypto_test_digest(i))
> +-            known_digest_nids[known_digest_nids_amount++] = digest_data[i].nid;
> +-    }
> +-}
> +-
> +-static const EVP_MD *get_digest_method(int nid)
> +-{
> +-    size_t i = get_digest_data_index(nid);
> +-
> +-    if (i == (size_t)-1)
> +-        return NULL;
> +-    return known_digest_methods[i];
> +-}
> +-
> +-static int get_digest_nids(const int **nids)
> +-{
> +-    *nids = known_digest_nids;
> +-    return known_digest_nids_amount;
> +-}
> +-
> +-static void destroy_digest_method(int nid)
> +-{
> +-    size_t i = get_digest_data_index(nid);
> +-
> +-    EVP_MD_meth_free(known_digest_methods[i]);
> +-    known_digest_methods[i] = NULL;
> +-}
> +-
> +-static void destroy_all_digest_methods(void)
> +-{
> +-    size_t i;
> +-
> +-    for (i = 0; i < OSSL_NELEM(digest_data); i++) {
> +-        destroy_digest_method(digest_data[i].nid);
> +-        OPENSSL_free(digest_driver_info[i].driver_name);
> +-        digest_driver_info[i].driver_name = NULL;
> +-    }
> +-}
> +-
> +-static int devcrypto_digests(ENGINE *e, const EVP_MD **digest,
> +-                             const int **nids, int nid)
> +-{
> +-    if (digest == NULL)
> +-        return get_digest_nids(nids);
> +-
> +-    *digest = get_digest_method(nid);
> +-
> +-    return *digest != NULL;
> +-}
> +-
> +-static void devcrypto_select_all_digests(int *digest_list)
> +-{
> +-    size_t i;
> +-
> +-    for (i = 0; i < OSSL_NELEM(digest_data); i++)
> +-        digest_list[i] = 1;
> +-}
> +-
> +-static int cryptodev_select_digest_cb(const char *str, int len, void *usr)
> +-{
> +-    int *digest_list = (int *)usr;
> +-    char *name;
> +-    const EVP_MD *EVP;
> +-    size_t i;
> +-
> +-    if (len == 0)
> +-        return 1;
> +-    if (usr == NULL || (name = OPENSSL_strndup(str, len)) == NULL)
> +-        return 0;
> +-    EVP = EVP_get_digestbyname(name);
> +-    if (EVP == NULL)
> +-        fprintf(stderr, "devcrypto: unknown digest %s\n", name);
> +-    else if ((i = find_digest_data_index(EVP_MD_type(EVP))) != (size_t)-1)
> +-        digest_list[i] = 1;
> +-    else
> +-        fprintf(stderr, "devcrypto: digest %s not available\n", name);
> +-    OPENSSL_free(name);
> +-    return 1;
> +-}
> +-
> +-static void dump_digest_info(void)
> +-{
> +-    size_t i;
> +-    const char *name;
> +-
> +-    fprintf (stderr, "Information about digests supported by the /dev/crypto"
> +-             " engine:\n");
> +-#ifndef CIOCGSESSINFO
> +-    fprintf(stderr, "CIOCGSESSINFO (session info call) unavailable\n");
> +-#endif
> +-
> +-    for (i = 0; i < OSSL_NELEM(digest_data); i++) {
> +-        name = OBJ_nid2sn(digest_data[i].nid);
> +-        fprintf (stderr, "Digest %s, NID=%d, /dev/crypto info: id=%d, driver=%s",
> +-                 name ? name : "unknown", digest_data[i].nid,
> +-                 digest_data[i].devcryptoid,
> +-                 digest_driver_info[i].driver_name ? digest_driver_info[i].driver_name : "unknown");
> +-        if (digest_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCGSESSION) {
> +-            fprintf (stderr, ". CIOCGSESSION (session open) failed\n");
> +-            continue;
> +-        }
> +-        if (digest_driver_info[i].accelerated == DEVCRYPTO_ACCELERATED)
> +-            fprintf(stderr, " (hw accelerated)");
> +-        else if (digest_driver_info[i].accelerated == DEVCRYPTO_NOT_ACCELERATED)
> +-            fprintf(stderr, " (software)");
> +-        else
> +-            fprintf(stderr, " (acceleration status unknown)");
> +-        if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_FAILURE)
> +-            fprintf (stderr, ". Cipher setup failed\n");
> +-        else if (digest_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCCPHASH)
> +-            fprintf(stderr, ", CIOCCPHASH failed\n");
> +-        else
> +-            fprintf(stderr, ", CIOCCPHASH capable\n");
> +-    }
> +-    fprintf(stderr, "\n");
> +-}
> +-
> +-#endif
> +-
> +-/******************************************************************************
> +- *
> +- * CONTROL COMMANDS
> +- *
> +- *****/
> +-
> +-#define DEVCRYPTO_CMD_USE_SOFTDRIVERS ENGINE_CMD_BASE
> +-#define DEVCRYPTO_CMD_CIPHERS (ENGINE_CMD_BASE + 1)
> +-#define DEVCRYPTO_CMD_DIGESTS (ENGINE_CMD_BASE + 2)
> +-#define DEVCRYPTO_CMD_DUMP_INFO (ENGINE_CMD_BASE + 3)
> +-
> +-/* Helper macros for CPP string composition */
> +-#ifndef OPENSSL_MSTR
> +-# define OPENSSL_MSTR_HELPER(x) #x
> +-# define OPENSSL_MSTR(x) OPENSSL_MSTR_HELPER(x)
> +-#endif
> +-
> +-static const ENGINE_CMD_DEFN devcrypto_cmds[] = {
> +-#ifdef CIOCGSESSINFO
> +-   {DEVCRYPTO_CMD_USE_SOFTDRIVERS,
> +-    "USE_SOFTDRIVERS",
> +-    "specifies whether to use software (not accelerated) drivers ("
> +-        OPENSSL_MSTR(DEVCRYPTO_REQUIRE_ACCELERATED) "=use only accelerated drivers, "
> +-        OPENSSL_MSTR(DEVCRYPTO_USE_SOFTWARE) "=allow all drivers, "
> +-        OPENSSL_MSTR(DEVCRYPTO_REJECT_SOFTWARE)
> +-        "=use if acceleration can't be determined) [default="
> +-        OPENSSL_MSTR(DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS) "]",
> +-    ENGINE_CMD_FLAG_NUMERIC},
> +-#endif
> +-
> +-   {DEVCRYPTO_CMD_CIPHERS,
> +-    "CIPHERS",
> +-    "either ALL, NONE, or a comma-separated list of ciphers to enable [default=ALL]",
> +-    ENGINE_CMD_FLAG_STRING},
> +-
> +-#ifdef IMPLEMENT_DIGEST
> +-   {DEVCRYPTO_CMD_DIGESTS,
> +-    "DIGESTS",
> +-    "either ALL, NONE, or a comma-separated list of digests to enable [default=ALL]",
> +-    ENGINE_CMD_FLAG_STRING},
> +-#endif
> +-
> +-   {DEVCRYPTO_CMD_DUMP_INFO,
> +-    "DUMP_INFO",
> +-    "dump info about each algorithm to stderr; use 'openssl engine -pre DUMP_INFO devcrypto'",
> +-    ENGINE_CMD_FLAG_NO_INPUT},
> +-
> +-   {0, NULL, NULL, 0}
> +-};
> +-
> +-static int devcrypto_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
> +-{
> +-    int *new_list;
> +-    switch (cmd) {
> +-#ifdef CIOCGSESSINFO
> +-    case DEVCRYPTO_CMD_USE_SOFTDRIVERS:
> +-        switch (i) {
> +-        case DEVCRYPTO_REQUIRE_ACCELERATED:
> +-        case DEVCRYPTO_USE_SOFTWARE:
> +-        case DEVCRYPTO_REJECT_SOFTWARE:
> +-            break;
> +-        default:
> +-            fprintf(stderr, "devcrypto: invalid value (%ld) for USE_SOFTDRIVERS\n", i);
> +-            return 0;
> +-        }
> +-        if (use_softdrivers == i)
> +-            return 1;
> +-        use_softdrivers = i;
> +-#ifdef IMPLEMENT_DIGEST
> +-        rebuild_known_digest_nids(e);
> +-#endif
> +-        rebuild_known_cipher_nids(e);
> +-        return 1;
> +-#endif /* CIOCGSESSINFO */
> +-
> +-    case DEVCRYPTO_CMD_CIPHERS:
> +-        if (p == NULL)
> +-            return 1;
> +-        if (strcasecmp((const char *)p, "ALL") == 0) {
> +-            devcrypto_select_all_ciphers(selected_ciphers);
> +-        } else if (strcasecmp((const char*)p, "NONE") == 0) {
> +-            memset(selected_ciphers, 0, sizeof(selected_ciphers));
> +-        } else {
> +-            new_list=OPENSSL_zalloc(sizeof(selected_ciphers));
> +-            if (!CONF_parse_list(p, ',', 1, cryptodev_select_cipher_cb, new_list)) {
> +-                OPENSSL_free(new_list);
> +-                return 0;
> +-            }
> +-            memcpy(selected_ciphers, new_list, sizeof(selected_ciphers));
> +-            OPENSSL_free(new_list);
> +-        }
> +-        rebuild_known_cipher_nids(e);
> +-        return 1;
> +-
> +-#ifdef IMPLEMENT_DIGEST
> +-    case DEVCRYPTO_CMD_DIGESTS:
> +-        if (p == NULL)
> +-            return 1;
> +-        if (strcasecmp((const char *)p, "ALL") == 0) {
> +-            devcrypto_select_all_digests(selected_digests);
> +-        } else if (strcasecmp((const char*)p, "NONE") == 0) {
> +-            memset(selected_digests, 0, sizeof(selected_digests));
> +-        } else {
> +-            new_list=OPENSSL_zalloc(sizeof(selected_digests));
> +-            if (!CONF_parse_list(p, ',', 1, cryptodev_select_digest_cb, new_list)) {
> +-                OPENSSL_free(new_list);
> +-                return 0;
> +-            }
> +-            memcpy(selected_digests, new_list, sizeof(selected_digests));
> +-            OPENSSL_free(new_list);
> +-        }
> +-        rebuild_known_digest_nids(e);
> +-        return 1;
> +-#endif /* IMPLEMENT_DIGEST */
> +-
> +-    case DEVCRYPTO_CMD_DUMP_INFO:
> +-        dump_cipher_info();
> +-#ifdef IMPLEMENT_DIGEST
> +-        dump_digest_info();
> +-#endif
> +-        return 1;
> +-
> +-    default:
> +-        break;
> +-    }
> +-    return 0;
> +-}
> +-
> +-/******************************************************************************
> +- *
> +- * LOAD / UNLOAD
> +- *
> +- *****/
> +-
> +-static int devcrypto_unload(ENGINE *e)
> +-{
> +-    destroy_all_cipher_methods();
> +-#ifdef IMPLEMENT_DIGEST
> +-    destroy_all_digest_methods();
> +-#endif
> +-
> +-    close(cfd);
> +-
> +-    return 1;
> +-}
> +-/*
> +- * This engine is always built into libcrypto, so it doesn't offer any
> +- * ability to be dynamically loadable.
> +- */
> +-void engine_load_devcrypto_int()
> +-{
> +-    ENGINE *e = NULL;
> +-    int fd;
> +-
> +-    if ((fd = open("/dev/crypto", O_RDWR, 0)) < 0) {
> +-#ifndef ENGINE_DEVCRYPTO_DEBUG
> +-        if (errno != ENOENT)
> +-#endif
> +-            fprintf(stderr, "Could not open /dev/crypto: %s\n", strerror(errno));
> +-        return;
> +-    }
> +-
> +-#ifdef CRIOGET
> +-    if (ioctl(fd, CRIOGET, &cfd) < 0) {
> +-        fprintf(stderr, "Could not create crypto fd: %s\n", strerror(errno));
> +-        close(fd);
> +-        cfd = -1;
> +-        return;
> +-    }
> +-    close(fd);
> +-#else
> +-    cfd = fd;
> +-#endif
> +-
> +-    if ((e = ENGINE_new()) == NULL
> +-        || !ENGINE_set_destroy_function(e, devcrypto_unload)) {
> +-        ENGINE_free(e);
> +-        /*
> +-         * We know that devcrypto_unload() won't be called when one of the
> +-         * above two calls have failed, so we close cfd explicitly here to
> +-         * avoid leaking resources.
> +-         */
> +-        close(cfd);
> +-        return;
> +-    }
> +-
> +-    prepare_cipher_methods();
> +-#ifdef IMPLEMENT_DIGEST
> +-    prepare_digest_methods();
> +-#endif
> +-
> +-    if (!ENGINE_set_id(e, "devcrypto")
> +-        || !ENGINE_set_name(e, "/dev/crypto engine")
> +-        || !ENGINE_set_cmd_defns(e, devcrypto_cmds)
> +-        || !ENGINE_set_ctrl_function(e, devcrypto_ctrl)
> +-
> +-/*
> +- * Asymmetric ciphers aren't well supported with /dev/crypto.  Among the BSD
> +- * implementations, it seems to only exist in FreeBSD, and regarding the
> +- * parameters in its crypt_kop, the manual crypto(4) has this to say:
> +- *
> +- *    The semantics of these arguments are currently undocumented.
> +- *
> +- * Reading through the FreeBSD source code doesn't give much more than
> +- * their CRK_MOD_EXP implementation for ubsec.
> +- *
> +- * It doesn't look much better with cryptodev-linux.  They have the crypt_kop
> +- * structure as well as the command (CRK_*) in cryptodev.h, but no support
> +- * seems to be implemented at all for the moment.
> +- *
> +- * At the time of writing, it seems impossible to write proper support for
> +- * FreeBSD's asym features without some very deep knowledge and access to
> +- * specific kernel modules.
> +- *
> +- * /Richard Levitte, 2017-05-11
> +- */
> +-#if 0
> +-# ifndef OPENSSL_NO_RSA
> +-        || !ENGINE_set_RSA(e, devcrypto_rsa)
> +-# endif
> +-# ifndef OPENSSL_NO_DSA
> +-        || !ENGINE_set_DSA(e, devcrypto_dsa)
> +-# endif
> +-# ifndef OPENSSL_NO_DH
> +-        || !ENGINE_set_DH(e, devcrypto_dh)
> +-# endif
> +-# ifndef OPENSSL_NO_EC
> +-        || !ENGINE_set_EC(e, devcrypto_ec)
> +-# endif
> +-#endif
> +-        || !ENGINE_set_ciphers(e, devcrypto_ciphers)
> +-#ifdef IMPLEMENT_DIGEST
> +-        || !ENGINE_set_digests(e, devcrypto_digests)
> +-#endif
> +-        ) {
> +-        ENGINE_free(e);
> +-        return;
> +-    }
> +-
> +-    ENGINE_add(e);
> +-    ENGINE_free(e);          /* Loose our local reference */
> +-    ERR_clear_error();
> +-}
> +--- a/crypto/init.c
> ++++ b/crypto/init.c
> +@@ -329,18 +329,6 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_engine_
> +     engine_load_openssl_int();
> +     return 1;
> + }
> +-# ifndef OPENSSL_NO_DEVCRYPTOENG
> +-static CRYPTO_ONCE engine_devcrypto = CRYPTO_ONCE_STATIC_INIT;
> +-DEFINE_RUN_ONCE_STATIC(ossl_init_engine_devcrypto)
> +-{
> +-#  ifdef OPENSSL_INIT_DEBUG
> +-    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_devcrypto: "
> +-                    "engine_load_devcrypto_int()\n");
> +-#  endif
> +-    engine_load_devcrypto_int();
> +-    return 1;
> +-}
> +-# endif
> +
> + # ifndef OPENSSL_NO_RDRAND
> + static CRYPTO_ONCE engine_rdrand = CRYPTO_ONCE_STATIC_INIT;
> +@@ -365,6 +353,18 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_engine_
> +     return 1;
> + }
> + # ifndef OPENSSL_NO_STATIC_ENGINE
> ++#  ifndef OPENSSL_NO_DEVCRYPTOENG
> ++static CRYPTO_ONCE engine_devcrypto = CRYPTO_ONCE_STATIC_INIT;
> ++DEFINE_RUN_ONCE_STATIC(ossl_init_engine_devcrypto)
> ++{
> ++#   ifdef OPENSSL_INIT_DEBUG
> ++    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_devcrypto: "
> ++                    "engine_load_devcrypto_int()\n");
> ++#   endif
> ++    engine_load_devcrypto_int();
> ++    return 1;
> ++}
> ++#  endif
> + #  if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_HW_PADLOCK)
> + static CRYPTO_ONCE engine_padlock = CRYPTO_ONCE_STATIC_INIT;
> + DEFINE_RUN_ONCE_STATIC(ossl_init_engine_padlock)
> +@@ -713,11 +713,6 @@ int OPENSSL_init_crypto(uint64_t opts, c
> +     if ((opts & OPENSSL_INIT_ENGINE_OPENSSL)
> +             && !RUN_ONCE(&engine_openssl, ossl_init_engine_openssl))
> +         return 0;
> +-# if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_DEVCRYPTOENG)
> +-    if ((opts & OPENSSL_INIT_ENGINE_CRYPTODEV)
> +-            && !RUN_ONCE(&engine_devcrypto, ossl_init_engine_devcrypto))
> +-        return 0;
> +-# endif
> + # ifndef OPENSSL_NO_RDRAND
> +     if ((opts & OPENSSL_INIT_ENGINE_RDRAND)
> +             && !RUN_ONCE(&engine_rdrand, ossl_init_engine_rdrand))
> +@@ -727,6 +722,11 @@ int OPENSSL_init_crypto(uint64_t opts, c
> +             && !RUN_ONCE(&engine_dynamic, ossl_init_engine_dynamic))
> +         return 0;
> + # ifndef OPENSSL_NO_STATIC_ENGINE
> ++#  ifndef OPENSSL_NO_DEVCRYPTOENG
> ++    if ((opts & OPENSSL_INIT_ENGINE_CRYPTODEV)
> ++            && !RUN_ONCE(&engine_devcrypto, ossl_init_engine_devcrypto))
> ++        return 0;
> ++#  endif
> + #  if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_HW_PADLOCK)
> +     if ((opts & OPENSSL_INIT_ENGINE_PADLOCK)
> +             && !RUN_ONCE(&engine_padlock, ossl_init_engine_padlock))
> +--- a/engines/build.info
> ++++ b/engines/build.info
> +@@ -11,6 +11,9 @@ IF[{- !$disabled{"engine"} -}]
> +     IF[{- !$disabled{afalgeng} -}]
> +       SOURCE[../libcrypto]=e_afalg.c
> +     ENDIF
> ++    IF[{- !$disabled{"devcryptoeng"} -}]
> ++      SOURCE[../libcrypto]=e_devcrypto.c
> ++    ENDIF
> +   ELSE
> +     IF[{- !$disabled{hw} && !$disabled{'hw-padlock'} -}]
> +       ENGINES=padlock
> +@@ -30,6 +33,12 @@ IF[{- !$disabled{"engine"} -}]
> +       DEPEND[afalg]=../libcrypto
> +       INCLUDE[afalg]= ../include
> +     ENDIF
> ++    IF[{- !$disabled{"devcryptoeng"} -}]
> ++      ENGINES=devcrypto
> ++      SOURCE[devcrypto]=e_devcrypto.c
> ++      DEPEND[devcrypto]=../libcrypto
> ++      INCLUDE[devcrypto]=../include
> ++    ENDIF
> +
> +     ENGINES_NO_INST=ossltest dasync
> +     SOURCE[dasync]=e_dasync.c
> +--- /dev/null
> ++++ b/engines/e_devcrypto.c
> +@@ -0,0 +1,1327 @@
> ++/*
> ++ * Copyright 2017-2021 The OpenSSL Project Authors. All Rights Reserved.
> ++ *
> ++ * Licensed under the OpenSSL license (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
> ++ */
> ++
> ++#include "../e_os.h"
> ++#include <string.h>
> ++#include <sys/types.h>
> ++#include <sys/stat.h>
> ++#include <fcntl.h>
> ++#include <sys/ioctl.h>
> ++#include <unistd.h>
> ++#include <assert.h>
> ++
> ++#include <openssl/conf.h>
> ++#include <openssl/evp.h>
> ++#include <openssl/err.h>
> ++#include <openssl/engine.h>
> ++#include <openssl/objects.h>
> ++#include <crypto/cryptodev.h>
> ++
> ++#include "crypto/engine.h"
> ++
> ++/* #define ENGINE_DEVCRYPTO_DEBUG */
> ++
> ++#if CRYPTO_ALGORITHM_MIN < CRYPTO_ALGORITHM_MAX
> ++# define CHECK_BSD_STYLE_MACROS
> ++#endif
> ++
> ++#define engine_devcrypto_id "devcrypto"
> ++
> ++/*
> ++ * ONE global file descriptor for all sessions.  This allows operations
> ++ * such as digest session data copying (see digest_copy()), but is also
> ++ * saner...  why re-open /dev/crypto for every session?
> ++ */
> ++static int cfd = -1;
> ++#define DEVCRYPTO_REQUIRE_ACCELERATED 0 /* require confirmation of acceleration */
> ++#define DEVCRYPTO_USE_SOFTWARE        1 /* allow software drivers */
> ++#define DEVCRYPTO_REJECT_SOFTWARE     2 /* only disallow confirmed software drivers */
> ++
> ++#define DEVCRYPTO_DEFAULT_USE_SOFTDRIVERS DEVCRYPTO_REJECT_SOFTWARE
> ++static int use_softdrivers = DEVCRYPTO_DEFAULT_USE_SOFTDRIVERS;
> ++
> ++/*
> ++ * cipher/digest status & acceleration definitions
> ++ * Make sure the defaults are set to 0
> ++ */
> ++struct driver_info_st {
> ++    enum devcrypto_status_t {
> ++        DEVCRYPTO_STATUS_FAILURE         = -3, /* unusable for other reason */
> ++        DEVCRYPTO_STATUS_NO_CIOCCPHASH   = -2, /* hash state copy not supported */
> ++        DEVCRYPTO_STATUS_NO_CIOCGSESSION = -1, /* session open failed */
> ++        DEVCRYPTO_STATUS_UNKNOWN         =  0, /* not tested yet */
> ++        DEVCRYPTO_STATUS_USABLE          =  1  /* algo can be used */
> ++    } status;
> ++
> ++    enum devcrypto_accelerated_t {
> ++        DEVCRYPTO_NOT_ACCELERATED        = -1, /* software implemented */
> ++        DEVCRYPTO_ACCELERATION_UNKNOWN   =  0, /* acceleration support unkown */
> ++        DEVCRYPTO_ACCELERATED            =  1  /* hardware accelerated */
> ++    } accelerated;
> ++
> ++    char *driver_name;
> ++};
> ++
> ++static int clean_devcrypto_session(struct session_op *sess) {
> ++    if (ioctl(cfd, CIOCFSESSION, &sess->ses) < 0) {
> ++        SYSerr(SYS_F_IOCTL, errno);
> ++        return 0;
> ++    }
> ++    memset(sess, 0, sizeof(struct session_op));
> ++    return 1;
> ++}
> ++
> ++/******************************************************************************
> ++ *
> ++ * Ciphers
> ++ *
> ++ * Because they all do the same basic operation, we have only one set of
> ++ * method functions for them all to share, and a mapping table between
> ++ * NIDs and cryptodev IDs, with all the necessary size data.
> ++ *
> ++ *****/
> ++
> ++struct cipher_ctx {
> ++    struct session_op sess;
> ++    int op;                      /* COP_ENCRYPT or COP_DECRYPT */
> ++    unsigned long mode;          /* EVP_CIPH_*_MODE */
> ++
> ++    /* to handle ctr mode being a stream cipher */
> ++    unsigned char partial[EVP_MAX_BLOCK_LENGTH];
> ++    unsigned int blocksize, num;
> ++};
> ++
> ++static const struct cipher_data_st {
> ++    int nid;
> ++    int blocksize;
> ++    int keylen;
> ++    int ivlen;
> ++    int flags;
> ++    int devcryptoid;
> ++} cipher_data[] = {
> ++#ifndef OPENSSL_NO_DES
> ++    { NID_des_cbc, 8, 8, 8, EVP_CIPH_CBC_MODE, CRYPTO_DES_CBC },
> ++    { NID_des_ede3_cbc, 8, 24, 8, EVP_CIPH_CBC_MODE, CRYPTO_3DES_CBC },
> ++#endif
> ++#ifndef OPENSSL_NO_BF
> ++    { NID_bf_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_BLF_CBC },
> ++#endif
> ++#ifndef OPENSSL_NO_CAST
> ++    { NID_cast5_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_CAST_CBC },
> ++#endif
> ++    { NID_aes_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
> ++    { NID_aes_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
> ++    { NID_aes_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
> ++#ifndef OPENSSL_NO_RC4
> ++    { NID_rc4, 1, 16, 0, EVP_CIPH_STREAM_CIPHER, CRYPTO_ARC4 },
> ++#endif
> ++#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_CTR)
> ++    { NID_aes_128_ctr, 16, 128 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
> ++    { NID_aes_192_ctr, 16, 192 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
> ++    { NID_aes_256_ctr, 16, 256 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
> ++#endif
> ++#if 0                            /* Not yet supported */
> ++    { NID_aes_128_xts, 16, 128 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS },
> ++    { NID_aes_256_xts, 16, 256 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS },
> ++#endif
> ++#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_ECB)
> ++    { NID_aes_128_ecb, 16, 128 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
> ++    { NID_aes_192_ecb, 16, 192 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
> ++    { NID_aes_256_ecb, 16, 256 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
> ++#endif
> ++#if 0                            /* Not yet supported */
> ++    { NID_aes_128_gcm, 16, 128 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
> ++    { NID_aes_192_gcm, 16, 192 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
> ++    { NID_aes_256_gcm, 16, 256 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
> ++#endif
> ++#ifndef OPENSSL_NO_CAMELLIA
> ++    { NID_camellia_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE,
> ++      CRYPTO_CAMELLIA_CBC },
> ++    { NID_camellia_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE,
> ++      CRYPTO_CAMELLIA_CBC },
> ++    { NID_camellia_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE,
> ++      CRYPTO_CAMELLIA_CBC },
> ++#endif
> ++};
> ++
> ++static size_t find_cipher_data_index(int nid)
> ++{
> ++    size_t i;
> ++
> ++    for (i = 0; i < OSSL_NELEM(cipher_data); i++)
> ++        if (nid == cipher_data[i].nid)
> ++            return i;
> ++    return (size_t)-1;
> ++}
> ++
> ++static size_t get_cipher_data_index(int nid)
> ++{
> ++    size_t i = find_cipher_data_index(nid);
> ++
> ++    if (i != (size_t)-1)
> ++        return i;
> ++
> ++    /*
> ++     * Code further down must make sure that only NIDs in the table above
> ++     * are used.  If any other NID reaches this function, there's a grave
> ++     * coding error further down.
> ++     */
> ++    assert("Code that never should be reached" == NULL);
> ++    return -1;
> ++}
> ++
> ++static const struct cipher_data_st *get_cipher_data(int nid)
> ++{
> ++    return &cipher_data[get_cipher_data_index(nid)];
> ++}
> ++
> ++/*
> ++ * Following are the three necessary functions to map OpenSSL functionality
> ++ * with cryptodev.
> ++ */
> ++
> ++static int cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
> ++                       const unsigned char *iv, int enc)
> ++{
> ++    struct cipher_ctx *cipher_ctx =
> ++        (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
> ++    const struct cipher_data_st *cipher_d =
> ++        get_cipher_data(EVP_CIPHER_CTX_nid(ctx));
> ++
> ++    /* cleanup a previous session */
> ++    if (cipher_ctx->sess.ses != 0 &&
> ++        clean_devcrypto_session(&cipher_ctx->sess) == 0)
> ++        return 0;
> ++
> ++    cipher_ctx->sess.cipher = cipher_d->devcryptoid;
> ++    cipher_ctx->sess.keylen = cipher_d->keylen;
> ++    cipher_ctx->sess.key = (void *)key;
> ++    cipher_ctx->op = enc ? COP_ENCRYPT : COP_DECRYPT;
> ++    cipher_ctx->mode = cipher_d->flags & EVP_CIPH_MODE;
> ++    cipher_ctx->blocksize = cipher_d->blocksize;
> ++    if (ioctl(cfd, CIOCGSESSION, &cipher_ctx->sess) < 0) {
> ++        SYSerr(SYS_F_IOCTL, errno);
> ++        return 0;
> ++    }
> ++
> ++    return 1;
> ++}
> ++
> ++static int cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
> ++                            const unsigned char *in, size_t inl)
> ++{
> ++    struct cipher_ctx *cipher_ctx =
> ++        (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
> ++    struct crypt_op cryp;
> ++    unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx);
> ++#if !defined(COP_FLAG_WRITE_IV)
> ++    unsigned char saved_iv[EVP_MAX_IV_LENGTH];
> ++    const unsigned char *ivptr;
> ++    size_t nblocks, ivlen;
> ++#endif
> ++
> ++    memset(&cryp, 0, sizeof(cryp));
> ++    cryp.ses = cipher_ctx->sess.ses;
> ++    cryp.len = inl;
> ++    cryp.src = (void *)in;
> ++    cryp.dst = (void *)out;
> ++    cryp.iv = (void *)iv;
> ++    cryp.op = cipher_ctx->op;
> ++#if !defined(COP_FLAG_WRITE_IV)
> ++    cryp.flags = 0;
> ++
> ++    ivlen = EVP_CIPHER_CTX_iv_length(ctx);
> ++    if (ivlen > 0)
> ++        switch (cipher_ctx->mode) {
> ++        case EVP_CIPH_CBC_MODE:
> ++            assert(inl >= ivlen);
> ++            if (!EVP_CIPHER_CTX_encrypting(ctx)) {
> ++                ivptr = in + inl - ivlen;
> ++                memcpy(saved_iv, ivptr, ivlen);
> ++            }
> ++            break;
> ++
> ++        case EVP_CIPH_CTR_MODE:
> ++            break;
> ++
> ++        default: /* should not happen */
> ++            return 0;
> ++        }
> ++#else
> ++    cryp.flags = COP_FLAG_WRITE_IV;
> ++#endif
> ++
> ++    if (ioctl(cfd, CIOCCRYPT, &cryp) < 0) {
> ++        SYSerr(SYS_F_IOCTL, errno);
> ++        return 0;
> ++    }
> ++
> ++#if !defined(COP_FLAG_WRITE_IV)
> ++    if (ivlen > 0)
> ++        switch (cipher_ctx->mode) {
> ++        case EVP_CIPH_CBC_MODE:
> ++            assert(inl >= ivlen);
> ++            if (EVP_CIPHER_CTX_encrypting(ctx))
> ++                ivptr = out + inl - ivlen;
> ++            else
> ++                ivptr = saved_iv;
> ++
> ++            memcpy(iv, ivptr, ivlen);
> ++            break;
> ++
> ++        case EVP_CIPH_CTR_MODE:
> ++            nblocks = (inl + cipher_ctx->blocksize - 1)
> ++                      / cipher_ctx->blocksize;
> ++            do {
> ++                ivlen--;
> ++                nblocks += iv[ivlen];
> ++                iv[ivlen] = (uint8_t) nblocks;
> ++                nblocks >>= 8;
> ++            } while (ivlen);
> ++            break;
> ++
> ++        default: /* should not happen */
> ++            return 0;
> ++        }
> ++#endif
> ++
> ++    return 1;
> ++}
> ++
> ++static int ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
> ++                         const unsigned char *in, size_t inl)
> ++{
> ++    struct cipher_ctx *cipher_ctx =
> ++        (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
> ++    size_t nblocks, len;
> ++
> ++    /* initial partial block */
> ++    while (cipher_ctx->num && inl) {
> ++        (*out++) = *(in++) ^ cipher_ctx->partial[cipher_ctx->num];
> ++        --inl;
> ++        cipher_ctx->num = (cipher_ctx->num + 1) % cipher_ctx->blocksize;
> ++    }
> ++
> ++    /* full blocks */
> ++    if (inl > (unsigned int) cipher_ctx->blocksize) {
> ++        nblocks = inl/cipher_ctx->blocksize;
> ++        len = nblocks * cipher_ctx->blocksize;
> ++        if (cipher_do_cipher(ctx, out, in, len) < 1)
> ++            return 0;
> ++        inl -= len;
> ++        out += len;
> ++        in += len;
> ++    }
> ++
> ++    /* final partial block */
> ++    if (inl) {
> ++        memset(cipher_ctx->partial, 0, cipher_ctx->blocksize);
> ++        if (cipher_do_cipher(ctx, cipher_ctx->partial, cipher_ctx->partial,
> ++            cipher_ctx->blocksize) < 1)
> ++            return 0;
> ++        while (inl--) {
> ++            out[cipher_ctx->num] = in[cipher_ctx->num]
> ++                                   ^ cipher_ctx->partial[cipher_ctx->num];
> ++            cipher_ctx->num++;
> ++        }
> ++    }
> ++
> ++    return 1;
> ++}
> ++
> ++static int cipher_ctrl(EVP_CIPHER_CTX *ctx, int type, int p1, void* p2)
> ++{
> ++    struct cipher_ctx *cipher_ctx =
> ++        (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
> ++    EVP_CIPHER_CTX *to_ctx = (EVP_CIPHER_CTX *)p2;
> ++    struct cipher_ctx *to_cipher_ctx;
> ++
> ++    switch (type) {
> ++    case EVP_CTRL_COPY:
> ++        if (cipher_ctx == NULL)
> ++            return 1;
> ++        /* when copying the context, a new session needs to be initialized */
> ++        to_cipher_ctx =
> ++            (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(to_ctx);
> ++        memset(&to_cipher_ctx->sess, 0, sizeof(to_cipher_ctx->sess));
> ++        return cipher_init(to_ctx, cipher_ctx->sess.key, EVP_CIPHER_CTX_iv(ctx),
> ++                           (cipher_ctx->op == COP_ENCRYPT));
> ++
> ++    case EVP_CTRL_INIT:
> ++        memset(&cipher_ctx->sess, 0, sizeof(cipher_ctx->sess));
> ++        return 1;
> ++
> ++    default:
> ++        break;
> ++    }
> ++
> ++    return -1;
> ++}
> ++
> ++static int cipher_cleanup(EVP_CIPHER_CTX *ctx)
> ++{
> ++    struct cipher_ctx *cipher_ctx =
> ++        (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
> ++
> ++    return clean_devcrypto_session(&cipher_ctx->sess);
> ++}
> ++
> ++/*
> ++ * Keep tables of known nids, associated methods, selected ciphers, and driver
> ++ * info.
> ++ * Note that known_cipher_nids[] isn't necessarily indexed the same way as
> ++ * cipher_data[] above, which the other tables are.
> ++ */
> ++static int known_cipher_nids[OSSL_NELEM(cipher_data)];
> ++static int known_cipher_nids_amount = -1; /* -1 indicates not yet initialised */
> ++static EVP_CIPHER *known_cipher_methods[OSSL_NELEM(cipher_data)] = { NULL, };
> ++static int selected_ciphers[OSSL_NELEM(cipher_data)];
> ++static struct driver_info_st cipher_driver_info[OSSL_NELEM(cipher_data)];
> ++
> ++
> ++static int devcrypto_test_cipher(size_t cipher_data_index)
> ++{
> ++    return (cipher_driver_info[cipher_data_index].status == DEVCRYPTO_STATUS_USABLE
> ++            && selected_ciphers[cipher_data_index] == 1
> ++            && (cipher_driver_info[cipher_data_index].accelerated
> ++                    == DEVCRYPTO_ACCELERATED
> ++                || use_softdrivers == DEVCRYPTO_USE_SOFTWARE
> ++                || (cipher_driver_info[cipher_data_index].accelerated
> ++                        != DEVCRYPTO_NOT_ACCELERATED
> ++                    && use_softdrivers == DEVCRYPTO_REJECT_SOFTWARE)));
> ++}
> ++
> ++static void prepare_cipher_methods(void)
> ++{
> ++    size_t i;
> ++    struct session_op sess;
> ++    unsigned long cipher_mode;
> ++#ifdef CIOCGSESSINFO
> ++    struct session_info_op siop;
> ++#endif
> ++
> ++    memset(&cipher_driver_info, 0, sizeof(cipher_driver_info));
> ++
> ++    memset(&sess, 0, sizeof(sess));
> ++    sess.key = (void *)"01234567890123456789012345678901234567890123456789";
> ++
> ++    for (i = 0, known_cipher_nids_amount = 0;
> ++         i < OSSL_NELEM(cipher_data); i++) {
> ++
> ++        selected_ciphers[i] = 1;
> ++        /*
> ++         * Check that the cipher is usable
> ++         */
> ++        sess.cipher = cipher_data[i].devcryptoid;
> ++        sess.keylen = cipher_data[i].keylen;
> ++        if (ioctl(cfd, CIOCGSESSION, &sess) < 0) {
> ++            cipher_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;
> ++            continue;
> ++        }
> ++
> ++        cipher_mode = cipher_data[i].flags & EVP_CIPH_MODE;
> ++
> ++        if ((known_cipher_methods[i] =
> ++                 EVP_CIPHER_meth_new(cipher_data[i].nid,
> ++                                     cipher_mode == EVP_CIPH_CTR_MODE ? 1 :
> ++                                                    cipher_data[i].blocksize,
> ++                                     cipher_data[i].keylen)) == NULL
> ++            || !EVP_CIPHER_meth_set_iv_length(known_cipher_methods[i],
> ++                                              cipher_data[i].ivlen)
> ++            || !EVP_CIPHER_meth_set_flags(known_cipher_methods[i],
> ++                                          cipher_data[i].flags
> ++                                          | EVP_CIPH_CUSTOM_COPY
> ++                                          | EVP_CIPH_CTRL_INIT
> ++                                          | EVP_CIPH_FLAG_DEFAULT_ASN1)
> ++            || !EVP_CIPHER_meth_set_init(known_cipher_methods[i], cipher_init)
> ++            || !EVP_CIPHER_meth_set_do_cipher(known_cipher_methods[i],
> ++                                     cipher_mode == EVP_CIPH_CTR_MODE ?
> ++                                              ctr_do_cipher :
> ++                                              cipher_do_cipher)
> ++            || !EVP_CIPHER_meth_set_ctrl(known_cipher_methods[i], cipher_ctrl)
> ++            || !EVP_CIPHER_meth_set_cleanup(known_cipher_methods[i],
> ++                                            cipher_cleanup)
> ++            || !EVP_CIPHER_meth_set_impl_ctx_size(known_cipher_methods[i],
> ++                                                  sizeof(struct cipher_ctx))) {
> ++            cipher_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
> ++            EVP_CIPHER_meth_free(known_cipher_methods[i]);
> ++            known_cipher_methods[i] = NULL;
> ++        } else {
> ++            cipher_driver_info[i].status = DEVCRYPTO_STATUS_USABLE;
> ++#ifdef CIOCGSESSINFO
> ++            siop.ses = sess.ses;
> ++            if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0) {
> ++                cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;
> ++            } else {
> ++                cipher_driver_info[i].driver_name =
> ++                    OPENSSL_strndup(siop.cipher_info.cra_driver_name,
> ++                                    CRYPTODEV_MAX_ALG_NAME);
> ++                if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY))
> ++                    cipher_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;
> ++                else
> ++                    cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;
> ++            }
> ++#endif /* CIOCGSESSINFO */
> ++        }
> ++        ioctl(cfd, CIOCFSESSION, &sess.ses);
> ++        if (devcrypto_test_cipher(i)) {
> ++            known_cipher_nids[known_cipher_nids_amount++] =
> ++                cipher_data[i].nid;
> ++        }
> ++    }
> ++}
> ++
> ++static void rebuild_known_cipher_nids(ENGINE *e)
> ++{
> ++    size_t i;
> ++
> ++    for (i = 0, known_cipher_nids_amount = 0; i < OSSL_NELEM(cipher_data); i++) {
> ++        if (devcrypto_test_cipher(i))
> ++            known_cipher_nids[known_cipher_nids_amount++] = cipher_data[i].nid;
> ++    }
> ++    ENGINE_unregister_ciphers(e);
> ++    ENGINE_register_ciphers(e);
> ++}
> ++
> ++static const EVP_CIPHER *get_cipher_method(int nid)
> ++{
> ++    size_t i = get_cipher_data_index(nid);
> ++
> ++    if (i == (size_t)-1)
> ++        return NULL;
> ++    return known_cipher_methods[i];
> ++}
> ++
> ++static int get_cipher_nids(const int **nids)
> ++{
> ++    *nids = known_cipher_nids;
> ++    return known_cipher_nids_amount;
> ++}
> ++
> ++static void destroy_cipher_method(int nid)
> ++{
> ++    size_t i = get_cipher_data_index(nid);
> ++
> ++    EVP_CIPHER_meth_free(known_cipher_methods[i]);
> ++    known_cipher_methods[i] = NULL;
> ++}
> ++
> ++static void destroy_all_cipher_methods(void)
> ++{
> ++    size_t i;
> ++
> ++    for (i = 0; i < OSSL_NELEM(cipher_data); i++) {
> ++        destroy_cipher_method(cipher_data[i].nid);
> ++        OPENSSL_free(cipher_driver_info[i].driver_name);
> ++        cipher_driver_info[i].driver_name = NULL;
> ++    }
> ++}
> ++
> ++static int devcrypto_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
> ++                             const int **nids, int nid)
> ++{
> ++    if (cipher == NULL)
> ++        return get_cipher_nids(nids);
> ++
> ++    *cipher = get_cipher_method(nid);
> ++
> ++    return *cipher != NULL;
> ++}
> ++
> ++static void devcrypto_select_all_ciphers(int *cipher_list)
> ++{
> ++    size_t i;
> ++
> ++    for (i = 0; i < OSSL_NELEM(cipher_data); i++)
> ++        cipher_list[i] = 1;
> ++}
> ++
> ++static int cryptodev_select_cipher_cb(const char *str, int len, void *usr)
> ++{
> ++    int *cipher_list = (int *)usr;
> ++    char *name;
> ++    const EVP_CIPHER *EVP;
> ++    size_t i;
> ++
> ++    if (len == 0)
> ++        return 1;
> ++    if (usr == NULL || (name = OPENSSL_strndup(str, len)) == NULL)
> ++        return 0;
> ++    EVP = EVP_get_cipherbyname(name);
> ++    if (EVP == NULL)
> ++        fprintf(stderr, "devcrypto: unknown cipher %s\n", name);
> ++    else if ((i = find_cipher_data_index(EVP_CIPHER_nid(EVP))) != (size_t)-1)
> ++        cipher_list[i] = 1;
> ++    else
> ++        fprintf(stderr, "devcrypto: cipher %s not available\n", name);
> ++    OPENSSL_free(name);
> ++    return 1;
> ++}
> ++
> ++static void dump_cipher_info(void)
> ++{
> ++    size_t i;
> ++    const char *name;
> ++
> ++    fprintf (stderr, "Information about ciphers supported by the /dev/crypto"
> ++             " engine:\n");
> ++#ifndef CIOCGSESSINFO
> ++    fprintf(stderr, "CIOCGSESSINFO (session info call) unavailable\n");
> ++#endif
> ++    for (i = 0; i < OSSL_NELEM(cipher_data); i++) {
> ++        name = OBJ_nid2sn(cipher_data[i].nid);
> ++        fprintf (stderr, "Cipher %s, NID=%d, /dev/crypto info: id=%d, ",
> ++                 name ? name : "unknown", cipher_data[i].nid,
> ++                 cipher_data[i].devcryptoid);
> ++        if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCGSESSION ) {
> ++            fprintf (stderr, "CIOCGSESSION (session open call) failed\n");
> ++            continue;
> ++        }
> ++        fprintf (stderr, "driver=%s ", cipher_driver_info[i].driver_name ?
> ++                 cipher_driver_info[i].driver_name : "unknown");
> ++        if (cipher_driver_info[i].accelerated == DEVCRYPTO_ACCELERATED)
> ++            fprintf(stderr, "(hw accelerated)");
> ++        else if (cipher_driver_info[i].accelerated == DEVCRYPTO_NOT_ACCELERATED)
> ++            fprintf(stderr, "(software)");
> ++        else
> ++            fprintf(stderr, "(acceleration status unknown)");
> ++        if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_FAILURE)
> ++            fprintf (stderr, ". Cipher setup failed");
> ++        fprintf(stderr, "\n");
> ++    }
> ++    fprintf(stderr, "\n");
> ++}
> ++
> ++/*
> ++ * We only support digests if the cryptodev implementation supports multiple
> ++ * data updates and session copying.  Otherwise, we would be forced to maintain
> ++ * a cache, which is perilous if there's a lot of data coming in (if someone
> ++ * wants to checksum an OpenSSL tarball, for example).
> ++ */
> ++#if defined(CIOCCPHASH) && defined(COP_FLAG_UPDATE) && defined(COP_FLAG_FINAL)
> ++#define IMPLEMENT_DIGEST
> ++
> ++/******************************************************************************
> ++ *
> ++ * Digests
> ++ *
> ++ * Because they all do the same basic operation, we have only one set of
> ++ * method functions for them all to share, and a mapping table between
> ++ * NIDs and cryptodev IDs, with all the necessary size data.
> ++ *
> ++ *****/
> ++
> ++struct digest_ctx {
> ++    struct session_op sess;
> ++    /* This signals that the init function was called, not that it succeeded. */
> ++    int init_called;
> ++    unsigned char digest_res[HASH_MAX_LEN];
> ++};
> ++
> ++static const struct digest_data_st {
> ++    int nid;
> ++    int blocksize;
> ++    int digestlen;
> ++    int devcryptoid;
> ++} digest_data[] = {
> ++#ifndef OPENSSL_NO_MD5
> ++    { NID_md5, /* MD5_CBLOCK */ 64, 16, CRYPTO_MD5 },
> ++#endif
> ++    { NID_sha1, SHA_CBLOCK, 20, CRYPTO_SHA1 },
> ++#ifndef OPENSSL_NO_RMD160
> ++# if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_RIPEMD160)
> ++    { NID_ripemd160, /* RIPEMD160_CBLOCK */ 64, 20, CRYPTO_RIPEMD160 },
> ++# endif
> ++#endif
> ++#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_224)
> ++    { NID_sha224, SHA256_CBLOCK, 224 / 8, CRYPTO_SHA2_224 },
> ++#endif
> ++#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_256)
> ++    { NID_sha256, SHA256_CBLOCK, 256 / 8, CRYPTO_SHA2_256 },
> ++#endif
> ++#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_384)
> ++    { NID_sha384, SHA512_CBLOCK, 384 / 8, CRYPTO_SHA2_384 },
> ++#endif
> ++#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_512)
> ++    { NID_sha512, SHA512_CBLOCK, 512 / 8, CRYPTO_SHA2_512 },
> ++#endif
> ++};
> ++
> ++static size_t find_digest_data_index(int nid)
> ++{
> ++    size_t i;
> ++
> ++    for (i = 0; i < OSSL_NELEM(digest_data); i++)
> ++        if (nid == digest_data[i].nid)
> ++            return i;
> ++    return (size_t)-1;
> ++}
> ++
> ++static size_t get_digest_data_index(int nid)
> ++{
> ++    size_t i = find_digest_data_index(nid);
> ++
> ++    if (i != (size_t)-1)
> ++        return i;
> ++
> ++    /*
> ++     * Code further down must make sure that only NIDs in the table above
> ++     * are used.  If any other NID reaches this function, there's a grave
> ++     * coding error further down.
> ++     */
> ++    assert("Code that never should be reached" == NULL);
> ++    return -1;
> ++}
> ++
> ++static const struct digest_data_st *get_digest_data(int nid)
> ++{
> ++    return &digest_data[get_digest_data_index(nid)];
> ++}
> ++
> ++/*
> ++ * Following are the five necessary functions to map OpenSSL functionality
> ++ * with cryptodev: init, update, final, cleanup, and copy.
> ++ */
> ++
> ++static int digest_init(EVP_MD_CTX *ctx)
> ++{
> ++    struct digest_ctx *digest_ctx =
> ++        (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
> ++    const struct digest_data_st *digest_d =
> ++        get_digest_data(EVP_MD_CTX_type(ctx));
> ++
> ++    digest_ctx->init_called = 1;
> ++
> ++    memset(&digest_ctx->sess, 0, sizeof(digest_ctx->sess));
> ++    digest_ctx->sess.mac = digest_d->devcryptoid;
> ++    if (ioctl(cfd, CIOCGSESSION, &digest_ctx->sess) < 0) {
> ++        SYSerr(SYS_F_IOCTL, errno);
> ++        return 0;
> ++    }
> ++
> ++    return 1;
> ++}
> ++
> ++static int digest_op(struct digest_ctx *ctx, const void *src, size_t srclen,
> ++                     void *res, unsigned int flags)
> ++{
> ++    struct crypt_op cryp;
> ++
> ++    memset(&cryp, 0, sizeof(cryp));
> ++    cryp.ses = ctx->sess.ses;
> ++    cryp.len = srclen;
> ++    cryp.src = (void *)src;
> ++    cryp.dst = NULL;
> ++    cryp.mac = res;
> ++    cryp.flags = flags;
> ++    return ioctl(cfd, CIOCCRYPT, &cryp);
> ++}
> ++
> ++static int digest_update(EVP_MD_CTX *ctx, const void *data, size_t count)
> ++{
> ++    struct digest_ctx *digest_ctx =
> ++        (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
> ++
> ++    if (count == 0)
> ++        return 1;
> ++
> ++    if (digest_ctx == NULL)
> ++        return 0;
> ++
> ++    if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {
> ++        if (digest_op(digest_ctx, data, count, digest_ctx->digest_res, 0) >= 0)
> ++            return 1;
> ++    } else if (digest_op(digest_ctx, data, count, NULL, COP_FLAG_UPDATE) >= 0) {
> ++        return 1;
> ++    }
> ++
> ++    SYSerr(SYS_F_IOCTL, errno);
> ++    return 0;
> ++}
> ++
> ++static int digest_final(EVP_MD_CTX *ctx, unsigned char *md)
> ++{
> ++    struct digest_ctx *digest_ctx =
> ++        (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
> ++
> ++    if (md == NULL || digest_ctx == NULL)
> ++        return 0;
> ++
> ++    if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {
> ++        memcpy(md, digest_ctx->digest_res, EVP_MD_CTX_size(ctx));
> ++    } else if (digest_op(digest_ctx, NULL, 0, md, COP_FLAG_FINAL) < 0) {
> ++        SYSerr(SYS_F_IOCTL, errno);
> ++        return 0;
> ++    }
> ++
> ++    return 1;
> ++}
> ++
> ++static int digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
>  +{
> -+#   ifdef OPENSSL_INIT_DEBUG
> -+    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_devcrypto: "
> -+                    "engine_load_devcrypto_int()\n");
> -+#   endif
> -+    engine_load_devcrypto_int();
> ++    struct digest_ctx *digest_from =
> ++        (struct digest_ctx *)EVP_MD_CTX_md_data(from);
> ++    struct digest_ctx *digest_to =
> ++        (struct digest_ctx *)EVP_MD_CTX_md_data(to);
> ++    struct cphash_op cphash;
> ++
> ++    if (digest_from == NULL || digest_from->init_called != 1)
> ++        return 1;
> ++
> ++    if (!digest_init(to)) {
> ++        SYSerr(SYS_F_IOCTL, errno);
> ++        return 0;
> ++    }
> ++
> ++    cphash.src_ses = digest_from->sess.ses;
> ++    cphash.dst_ses = digest_to->sess.ses;
> ++    if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) {
> ++        SYSerr(SYS_F_IOCTL, errno);
> ++        return 0;
> ++    }
>  +    return 1;
>  +}
> -+#  endif
> - #  if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_HW_PADLOCK)
> - static CRYPTO_ONCE engine_padlock = CRYPTO_ONCE_STATIC_INIT;
> - DEFINE_RUN_ONCE_STATIC(ossl_init_engine_padlock)
> -@@ -713,11 +713,6 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
> -     if ((opts & OPENSSL_INIT_ENGINE_OPENSSL)
> -             && !RUN_ONCE(&engine_openssl, ossl_init_engine_openssl))
> -         return 0;
> --# if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_DEVCRYPTOENG)
> --    if ((opts & OPENSSL_INIT_ENGINE_CRYPTODEV)
> --            && !RUN_ONCE(&engine_devcrypto, ossl_init_engine_devcrypto))
> --        return 0;
> --# endif
> - # ifndef OPENSSL_NO_RDRAND
> -     if ((opts & OPENSSL_INIT_ENGINE_RDRAND)
> -             && !RUN_ONCE(&engine_rdrand, ossl_init_engine_rdrand))
> -@@ -727,6 +722,11 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
> -             && !RUN_ONCE(&engine_dynamic, ossl_init_engine_dynamic))
> -         return 0;
> - # ifndef OPENSSL_NO_STATIC_ENGINE
> -+#  ifndef OPENSSL_NO_DEVCRYPTOENG
> -+    if ((opts & OPENSSL_INIT_ENGINE_CRYPTODEV)
> -+            && !RUN_ONCE(&engine_devcrypto, ossl_init_engine_devcrypto))
> ++
> ++static int digest_cleanup(EVP_MD_CTX *ctx)
> ++{
> ++    struct digest_ctx *digest_ctx =
> ++        (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
> ++
> ++    if (digest_ctx == NULL)
> ++        return 1;
> ++
> ++    return clean_devcrypto_session(&digest_ctx->sess);
> ++}
> ++
> ++/*
> ++ * Keep tables of known nids, associated methods, selected digests, and
> ++ * driver info.
> ++ * Note that known_digest_nids[] isn't necessarily indexed the same way as
> ++ * digest_data[] above, which the other tables are.
> ++ */
> ++static int known_digest_nids[OSSL_NELEM(digest_data)];
> ++static int known_digest_nids_amount = -1; /* -1 indicates not yet initialised */
> ++static EVP_MD *known_digest_methods[OSSL_NELEM(digest_data)] = { NULL, };
> ++static int selected_digests[OSSL_NELEM(digest_data)];
> ++static struct driver_info_st digest_driver_info[OSSL_NELEM(digest_data)];
> ++
> ++static int devcrypto_test_digest(size_t digest_data_index)
> ++{
> ++    return (digest_driver_info[digest_data_index].status == DEVCRYPTO_STATUS_USABLE
> ++            && selected_digests[digest_data_index] == 1
> ++            && (digest_driver_info[digest_data_index].accelerated
> ++                    == DEVCRYPTO_ACCELERATED
> ++                || use_softdrivers == DEVCRYPTO_USE_SOFTWARE
> ++                || (digest_driver_info[digest_data_index].accelerated
> ++                        != DEVCRYPTO_NOT_ACCELERATED
> ++                    && use_softdrivers == DEVCRYPTO_REJECT_SOFTWARE)));
> ++}
> ++
> ++static void rebuild_known_digest_nids(ENGINE *e)
> ++{
> ++    size_t i;
> ++
> ++    for (i = 0, known_digest_nids_amount = 0; i < OSSL_NELEM(digest_data); i++) {
> ++        if (devcrypto_test_digest(i))
> ++            known_digest_nids[known_digest_nids_amount++] = digest_data[i].nid;
> ++    }
> ++    ENGINE_unregister_digests(e);
> ++    ENGINE_register_digests(e);
> ++}
> ++
> ++static void prepare_digest_methods(void)
> ++{
> ++    size_t i;
> ++    struct session_op sess1, sess2;
> ++#ifdef CIOCGSESSINFO
> ++    struct session_info_op siop;
> ++#endif
> ++    struct cphash_op cphash;
> ++
> ++    memset(&digest_driver_info, 0, sizeof(digest_driver_info));
> ++
> ++    memset(&sess1, 0, sizeof(sess1));
> ++    memset(&sess2, 0, sizeof(sess2));
> ++
> ++    for (i = 0, known_digest_nids_amount = 0; i < OSSL_NELEM(digest_data);
> ++         i++) {
> ++
> ++        selected_digests[i] = 1;
> ++
> ++        /*
> ++         * Check that the digest is usable
> ++         */
> ++        sess1.mac = digest_data[i].devcryptoid;
> ++        sess2.ses = 0;
> ++        if (ioctl(cfd, CIOCGSESSION, &sess1) < 0) {
> ++            digest_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;
> ++            goto finish;
> ++        }
> ++
> ++#ifdef CIOCGSESSINFO
> ++        /* gather hardware acceleration info from the driver */
> ++        siop.ses = sess1.ses;
> ++        if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0) {
> ++            digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;
> ++        } else {
> ++            digest_driver_info[i].driver_name =
> ++                OPENSSL_strndup(siop.hash_info.cra_driver_name,
> ++                                CRYPTODEV_MAX_ALG_NAME);
> ++            if (siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)
> ++                digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;
> ++            else
> ++                digest_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;
> ++        }
> ++#endif
> ++
> ++        /* digest must be capable of hash state copy */
> ++        sess2.mac = sess1.mac;
> ++        if (ioctl(cfd, CIOCGSESSION, &sess2) < 0) {
> ++            digest_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
> ++            goto finish;
> ++        }
> ++        cphash.src_ses = sess1.ses;
> ++        cphash.dst_ses = sess2.ses;
> ++        if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) {
> ++            digest_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCCPHASH;
> ++            goto finish;
> ++        }
> ++        if ((known_digest_methods[i] = EVP_MD_meth_new(digest_data[i].nid,
> ++                                                       NID_undef)) == NULL
> ++            || !EVP_MD_meth_set_input_blocksize(known_digest_methods[i],
> ++                                                digest_data[i].blocksize)
> ++            || !EVP_MD_meth_set_result_size(known_digest_methods[i],
> ++                                            digest_data[i].digestlen)
> ++            || !EVP_MD_meth_set_init(known_digest_methods[i], digest_init)
> ++            || !EVP_MD_meth_set_update(known_digest_methods[i], digest_update)
> ++            || !EVP_MD_meth_set_final(known_digest_methods[i], digest_final)
> ++            || !EVP_MD_meth_set_copy(known_digest_methods[i], digest_copy)
> ++            || !EVP_MD_meth_set_cleanup(known_digest_methods[i], digest_cleanup)
> ++            || !EVP_MD_meth_set_app_datasize(known_digest_methods[i],
> ++                                             sizeof(struct digest_ctx))) {
> ++            digest_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
> ++            EVP_MD_meth_free(known_digest_methods[i]);
> ++            known_digest_methods[i] = NULL;
> ++            goto finish;
> ++        }
> ++        digest_driver_info[i].status = DEVCRYPTO_STATUS_USABLE;
> ++finish:
> ++        ioctl(cfd, CIOCFSESSION, &sess1.ses);
> ++        if (sess2.ses != 0)
> ++            ioctl(cfd, CIOCFSESSION, &sess2.ses);
> ++        if (devcrypto_test_digest(i))
> ++            known_digest_nids[known_digest_nids_amount++] = digest_data[i].nid;
> ++    }
> ++}
> ++
> ++static const EVP_MD *get_digest_method(int nid)
> ++{
> ++    size_t i = get_digest_data_index(nid);
> ++
> ++    if (i == (size_t)-1)
> ++        return NULL;
> ++    return known_digest_methods[i];
> ++}
> ++
> ++static int get_digest_nids(const int **nids)
> ++{
> ++    *nids = known_digest_nids;
> ++    return known_digest_nids_amount;
> ++}
> ++
> ++static void destroy_digest_method(int nid)
> ++{
> ++    size_t i = get_digest_data_index(nid);
> ++
> ++    EVP_MD_meth_free(known_digest_methods[i]);
> ++    known_digest_methods[i] = NULL;
> ++}
> ++
> ++static void destroy_all_digest_methods(void)
> ++{
> ++    size_t i;
> ++
> ++    for (i = 0; i < OSSL_NELEM(digest_data); i++) {
> ++        destroy_digest_method(digest_data[i].nid);
> ++        OPENSSL_free(digest_driver_info[i].driver_name);
> ++        digest_driver_info[i].driver_name = NULL;
> ++    }
> ++}
> ++
> ++static int devcrypto_digests(ENGINE *e, const EVP_MD **digest,
> ++                             const int **nids, int nid)
> ++{
> ++    if (digest == NULL)
> ++        return get_digest_nids(nids);
> ++
> ++    *digest = get_digest_method(nid);
> ++
> ++    return *digest != NULL;
> ++}
> ++
> ++static void devcrypto_select_all_digests(int *digest_list)
> ++{
> ++    size_t i;
> ++
> ++    for (i = 0; i < OSSL_NELEM(digest_data); i++)
> ++        digest_list[i] = 1;
> ++}
> ++
> ++static int cryptodev_select_digest_cb(const char *str, int len, void *usr)
> ++{
> ++    int *digest_list = (int *)usr;
> ++    char *name;
> ++    const EVP_MD *EVP;
> ++    size_t i;
> ++
> ++    if (len == 0)
> ++        return 1;
> ++    if (usr == NULL || (name = OPENSSL_strndup(str, len)) == NULL)
>  +        return 0;
> -+#  endif
> - #  if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_HW_PADLOCK)
> -     if ((opts & OPENSSL_INIT_ENGINE_PADLOCK)
> -             && !RUN_ONCE(&engine_padlock, ossl_init_engine_padlock))
> -diff --git a/engines/build.info b/engines/build.info
> -index 1db771971c..33a25d7004 100644
> ---- a/engines/build.info
> -+++ b/engines/build.info
> -@@ -11,6 +11,9 @@ IF[{- !$disabled{"engine"} -}]
> -     IF[{- !$disabled{afalgeng} -}]
> -       SOURCE[../libcrypto]=e_afalg.c
> -     ENDIF
> -+    IF[{- !$disabled{"devcryptoeng"} -}]
> -+      SOURCE[../libcrypto]=e_devcrypto.c
> -+    ENDIF
> -   ELSE
> -     IF[{- !$disabled{hw} && !$disabled{'hw-padlock'} -}]
> -       ENGINES=padlock
> -@@ -30,6 +33,12 @@ IF[{- !$disabled{"engine"} -}]
> -       DEPEND[afalg]=../libcrypto
> -       INCLUDE[afalg]= ../include
> -     ENDIF
> -+    IF[{- !$disabled{"devcryptoeng"} -}]
> -+      ENGINES=devcrypto
> -+      SOURCE[devcrypto]=e_devcrypto.c
> -+      DEPEND[devcrypto]=../libcrypto
> -+      INCLUDE[devcrypto]=../include
> -+    ENDIF
> -
> -     ENGINES_NO_INST=ossltest dasync
> -     SOURCE[dasync]=e_dasync.c
> -diff --git a/crypto/engine/eng_devcrypto.c b/engines/e_devcrypto.c
> -similarity index 95%
> -rename from crypto/engine/eng_devcrypto.c
> -rename to engines/e_devcrypto.c
> -index 2c1b52d572..eff1ed3a7d 100644
> ---- a/crypto/engine/eng_devcrypto.c
> -+++ b/engines/e_devcrypto.c
> -@@ -7,7 +7,7 @@
> -  * https://www.openssl.org/source/license.html
> -  */
> -
> --#include "e_os.h"
> -+#include "../e_os.h"
> - #include <string.h>
> - #include <sys/types.h>
> - #include <sys/stat.h>
> -@@ -31,18 +31,20 @@
> - # define CHECK_BSD_STYLE_MACROS
> - #endif
> -
> -+#define engine_devcrypto_id "devcrypto"
> ++    EVP = EVP_get_digestbyname(name);
> ++    if (EVP == NULL)
> ++        fprintf(stderr, "devcrypto: unknown digest %s\n", name);
> ++    else if ((i = find_digest_data_index(EVP_MD_type(EVP))) != (size_t)-1)
> ++        digest_list[i] = 1;
> ++    else
> ++        fprintf(stderr, "devcrypto: digest %s not available\n", name);
> ++    OPENSSL_free(name);
> ++    return 1;
> ++}
>  +
> - /*
> -  * ONE global file descriptor for all sessions.  This allows operations
> -  * such as digest session data copying (see digest_copy()), but is also
> -  * saner...  why re-open /dev/crypto for every session?
> -  */
> --static int cfd;
> -+static int cfd = -1;
> - #define DEVCRYPTO_REQUIRE_ACCELERATED 0 /* require confirmation of acceleration */
> - #define DEVCRYPTO_USE_SOFTWARE        1 /* allow software drivers */
> - #define DEVCRYPTO_REJECT_SOFTWARE     2 /* only disallow confirmed software drivers */
> -
> --#define DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS DEVCRYPTO_REJECT_SOFTWARE
> --static int use_softdrivers = DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS;
> -+#define DEVCRYPTO_DEFAULT_USE_SOFTDRIVERS DEVCRYPTO_REJECT_SOFTWARE
> -+static int use_softdrivers = DEVCRYPTO_DEFAULT_USE_SOFTDRIVERS;
> -
> - /*
> -  * cipher/digest status & acceleration definitions
> -@@ -1058,7 +1060,7 @@ static const ENGINE_CMD_DEFN devcrypto_cmds[] = {
> -         OPENSSL_MSTR(DEVCRYPTO_USE_SOFTWARE) "=allow all drivers, "
> -         OPENSSL_MSTR(DEVCRYPTO_REJECT_SOFTWARE)
> -         "=use if acceleration can't be determined) [default="
> --        OPENSSL_MSTR(DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS) "]",
> ++static void dump_digest_info(void)
> ++{
> ++    size_t i;
> ++    const char *name;
> ++
> ++    fprintf (stderr, "Information about digests supported by the /dev/crypto"
> ++             " engine:\n");
> ++#ifndef CIOCGSESSINFO
> ++    fprintf(stderr, "CIOCGSESSINFO (session info call) unavailable\n");
> ++#endif
> ++
> ++    for (i = 0; i < OSSL_NELEM(digest_data); i++) {
> ++        name = OBJ_nid2sn(digest_data[i].nid);
> ++        fprintf (stderr, "Digest %s, NID=%d, /dev/crypto info: id=%d, driver=%s",
> ++                 name ? name : "unknown", digest_data[i].nid,
> ++                 digest_data[i].devcryptoid,
> ++                 digest_driver_info[i].driver_name ? digest_driver_info[i].driver_name : "unknown");
> ++        if (digest_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCGSESSION) {
> ++            fprintf (stderr, ". CIOCGSESSION (session open) failed\n");
> ++            continue;
> ++        }
> ++        if (digest_driver_info[i].accelerated == DEVCRYPTO_ACCELERATED)
> ++            fprintf(stderr, " (hw accelerated)");
> ++        else if (digest_driver_info[i].accelerated == DEVCRYPTO_NOT_ACCELERATED)
> ++            fprintf(stderr, " (software)");
> ++        else
> ++            fprintf(stderr, " (acceleration status unknown)");
> ++        if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_FAILURE)
> ++            fprintf (stderr, ". Cipher setup failed\n");
> ++        else if (digest_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCCPHASH)
> ++            fprintf(stderr, ", CIOCCPHASH failed\n");
> ++        else
> ++            fprintf(stderr, ", CIOCCPHASH capable\n");
> ++    }
> ++    fprintf(stderr, "\n");
> ++}
> ++
> ++#endif
> ++
> ++/******************************************************************************
> ++ *
> ++ * CONTROL COMMANDS
> ++ *
> ++ *****/
> ++
> ++#define DEVCRYPTO_CMD_USE_SOFTDRIVERS ENGINE_CMD_BASE
> ++#define DEVCRYPTO_CMD_CIPHERS (ENGINE_CMD_BASE + 1)
> ++#define DEVCRYPTO_CMD_DIGESTS (ENGINE_CMD_BASE + 2)
> ++#define DEVCRYPTO_CMD_DUMP_INFO (ENGINE_CMD_BASE + 3)
> ++
> ++/* Helper macros for CPP string composition */
> ++#ifndef OPENSSL_MSTR
> ++# define OPENSSL_MSTR_HELPER(x) #x
> ++# define OPENSSL_MSTR(x) OPENSSL_MSTR_HELPER(x)
> ++#endif
> ++
> ++static const ENGINE_CMD_DEFN devcrypto_cmds[] = {
> ++#ifdef CIOCGSESSINFO
> ++   {DEVCRYPTO_CMD_USE_SOFTDRIVERS,
> ++    "USE_SOFTDRIVERS",
> ++    "specifies whether to use software (not accelerated) drivers ("
> ++        OPENSSL_MSTR(DEVCRYPTO_REQUIRE_ACCELERATED) "=use only accelerated drivers, "
> ++        OPENSSL_MSTR(DEVCRYPTO_USE_SOFTWARE) "=allow all drivers, "
> ++        OPENSSL_MSTR(DEVCRYPTO_REJECT_SOFTWARE)
> ++        "=use if acceleration can't be determined) [default="
>  +        OPENSSL_MSTR(DEVCRYPTO_DEFAULT_USE_SOFTDRIVERS) "]",
> -     ENGINE_CMD_FLAG_NUMERIC},
> - #endif
> -
> -@@ -1166,32 +1168,22 @@ static int devcrypto_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
> -  *
> -  *****/
> -
> --static int devcrypto_unload(ENGINE *e)
> --{
> --    destroy_all_cipher_methods();
> --#ifdef IMPLEMENT_DIGEST
> --    destroy_all_digest_methods();
> --#endif
> --
> --    close(cfd);
> --
> --    return 1;
> --}
> - /*
> -- * This engine is always built into libcrypto, so it doesn't offer any
> -- * ability to be dynamically loadable.
> ++    ENGINE_CMD_FLAG_NUMERIC},
> ++#endif
> ++
> ++   {DEVCRYPTO_CMD_CIPHERS,
> ++    "CIPHERS",
> ++    "either ALL, NONE, or a comma-separated list of ciphers to enable [default=ALL]",
> ++    ENGINE_CMD_FLAG_STRING},
> ++
> ++#ifdef IMPLEMENT_DIGEST
> ++   {DEVCRYPTO_CMD_DIGESTS,
> ++    "DIGESTS",
> ++    "either ALL, NONE, or a comma-separated list of digests to enable [default=ALL]",
> ++    ENGINE_CMD_FLAG_STRING},
> ++#endif
> ++
> ++   {DEVCRYPTO_CMD_DUMP_INFO,
> ++    "DUMP_INFO",
> ++    "dump info about each algorithm to stderr; use 'openssl engine -pre DUMP_INFO devcrypto'",
> ++    ENGINE_CMD_FLAG_NO_INPUT},
> ++
> ++   {0, NULL, NULL, 0}
> ++};
> ++
> ++static int devcrypto_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
> ++{
> ++    int *new_list;
> ++    switch (cmd) {
> ++#ifdef CIOCGSESSINFO
> ++    case DEVCRYPTO_CMD_USE_SOFTDRIVERS:
> ++        switch (i) {
> ++        case DEVCRYPTO_REQUIRE_ACCELERATED:
> ++        case DEVCRYPTO_USE_SOFTWARE:
> ++        case DEVCRYPTO_REJECT_SOFTWARE:
> ++            break;
> ++        default:
> ++            fprintf(stderr, "devcrypto: invalid value (%ld) for USE_SOFTDRIVERS\n", i);
> ++            return 0;
> ++        }
> ++        if (use_softdrivers == i)
> ++            return 1;
> ++        use_softdrivers = i;
> ++#ifdef IMPLEMENT_DIGEST
> ++        rebuild_known_digest_nids(e);
> ++#endif
> ++        rebuild_known_cipher_nids(e);
> ++        return 1;
> ++#endif /* CIOCGSESSINFO */
> ++
> ++    case DEVCRYPTO_CMD_CIPHERS:
> ++        if (p == NULL)
> ++            return 1;
> ++        if (strcasecmp((const char *)p, "ALL") == 0) {
> ++            devcrypto_select_all_ciphers(selected_ciphers);
> ++        } else if (strcasecmp((const char*)p, "NONE") == 0) {
> ++            memset(selected_ciphers, 0, sizeof(selected_ciphers));
> ++        } else {
> ++            new_list=OPENSSL_zalloc(sizeof(selected_ciphers));
> ++            if (!CONF_parse_list(p, ',', 1, cryptodev_select_cipher_cb, new_list)) {
> ++                OPENSSL_free(new_list);
> ++                return 0;
> ++            }
> ++            memcpy(selected_ciphers, new_list, sizeof(selected_ciphers));
> ++            OPENSSL_free(new_list);
> ++        }
> ++        rebuild_known_cipher_nids(e);
> ++        return 1;
> ++
> ++#ifdef IMPLEMENT_DIGEST
> ++    case DEVCRYPTO_CMD_DIGESTS:
> ++        if (p == NULL)
> ++            return 1;
> ++        if (strcasecmp((const char *)p, "ALL") == 0) {
> ++            devcrypto_select_all_digests(selected_digests);
> ++        } else if (strcasecmp((const char*)p, "NONE") == 0) {
> ++            memset(selected_digests, 0, sizeof(selected_digests));
> ++        } else {
> ++            new_list=OPENSSL_zalloc(sizeof(selected_digests));
> ++            if (!CONF_parse_list(p, ',', 1, cryptodev_select_digest_cb, new_list)) {
> ++                OPENSSL_free(new_list);
> ++                return 0;
> ++            }
> ++            memcpy(selected_digests, new_list, sizeof(selected_digests));
> ++            OPENSSL_free(new_list);
> ++        }
> ++        rebuild_known_digest_nids(e);
> ++        return 1;
> ++#endif /* IMPLEMENT_DIGEST */
> ++
> ++    case DEVCRYPTO_CMD_DUMP_INFO:
> ++        dump_cipher_info();
> ++#ifdef IMPLEMENT_DIGEST
> ++        dump_digest_info();
> ++#endif
> ++        return 1;
> ++
> ++    default:
> ++        break;
> ++    }
> ++    return 0;
> ++}
> ++
> ++/******************************************************************************
> ++ *
> ++ * LOAD / UNLOAD
> ++ *
> ++ *****/
> ++
> ++/*
>  + * Opens /dev/crypto
> -  */
> --void engine_load_devcrypto_int()
> ++ */
>  +static int open_devcrypto(void)
> - {
> --    ENGINE *e = NULL;
> -     int fd;
> -
> ++{
> ++    int fd;
> ++
>  +    if (cfd >= 0)
>  +        return 1;
>  +
> -     if ((fd = open("/dev/crypto", O_RDWR, 0)) < 0) {
> - #ifndef ENGINE_DEVCRYPTO_DEBUG
> -         if (errno != ENOENT)
> - #endif
> -             fprintf(stderr, "Could not open /dev/crypto: %s\n", strerror(errno));
> --        return;
> ++    if ((fd = open("/dev/crypto", O_RDWR, 0)) < 0) {
> ++#ifndef ENGINE_DEVCRYPTO_DEBUG
> ++        if (errno != ENOENT)
> ++#endif
> ++            fprintf(stderr, "Could not open /dev/crypto: %s\n", strerror(errno));
>  +        return 0;
> -     }
> -
> - #ifdef CRIOGET
> -@@ -1199,35 +1191,61 @@ void engine_load_devcrypto_int()
> -         fprintf(stderr, "Could not create crypto fd: %s\n", strerror(errno));
> -         close(fd);
> -         cfd = -1;
> --        return;
> ++    }
> ++
> ++#ifdef CRIOGET
> ++    if (ioctl(fd, CRIOGET, &cfd) < 0) {
> ++        fprintf(stderr, "Could not create crypto fd: %s\n", strerror(errno));
> ++        close(fd);
> ++        cfd = -1;
>  +        return 0;
> -     }
> -     close(fd);
> - #else
> -     cfd = fd;
> - #endif
> -
> --    if ((e = ENGINE_new()) == NULL
> --        || !ENGINE_set_destroy_function(e, devcrypto_unload)) {
> --        ENGINE_free(e);
> --        /*
> --         * We know that devcrypto_unload() won't be called when one of the
> --         * above two calls have failed, so we close cfd explicitly here to
> --         * avoid leaking resources.
> --         */
> --        close(cfd);
> --        return;
> ++    }
> ++    close(fd);
> ++#else
> ++    cfd = fd;
> ++#endif
> ++
>  +    return 1;
>  +}
>  +
> @@ -236,20 +2603,17 @@ index 2c1b52d572..eff1ed3a7d 100644
>  +    if (ret != 0) {
>  +        fprintf(stderr, "Error closing /dev/crypto: %s\n", strerror(errno));
>  +        return 0;
> -     }
> ++    }
>  +    return 1;
>  +}
> -
> --    prepare_cipher_methods();
> ++
>  +static int devcrypto_unload(ENGINE *e)
>  +{
>  +    destroy_all_cipher_methods();
> - #ifdef IMPLEMENT_DIGEST
> --    prepare_digest_methods();
> ++#ifdef IMPLEMENT_DIGEST
>  +    destroy_all_digest_methods();
> - #endif
> -
> --    if (!ENGINE_set_id(e, "devcrypto")
> ++#endif
> ++
>  +    close_devcrypto();
>  +
>  +    return 1;
> @@ -258,13 +2622,12 @@ index 2c1b52d572..eff1ed3a7d 100644
>  +static int bind_devcrypto(ENGINE *e) {
>  +
>  +    if (!ENGINE_set_id(e, engine_devcrypto_id)
> -         || !ENGINE_set_name(e, "/dev/crypto engine")
> ++        || !ENGINE_set_name(e, "/dev/crypto engine")
>  +        || !ENGINE_set_destroy_function(e, devcrypto_unload)
> -         || !ENGINE_set_cmd_defns(e, devcrypto_cmds)
> --        || !ENGINE_set_ctrl_function(e, devcrypto_ctrl)
> ++        || !ENGINE_set_cmd_defns(e, devcrypto_cmds)
>  +        || !ENGINE_set_ctrl_function(e, devcrypto_ctrl))
>  +        return 0;
> -
> ++
>  +    prepare_cipher_methods();
>  +#ifdef IMPLEMENT_DIGEST
>  +    prepare_digest_methods();
> @@ -274,34 +2637,40 @@ index 2c1b52d572..eff1ed3a7d 100644
>  +#ifdef IMPLEMENT_DIGEST
>  +        && ENGINE_set_digests(e, devcrypto_digests)
>  +#endif
> - /*
> -  * Asymmetric ciphers aren't well supported with /dev/crypto.  Among the BSD
> -  * implementations, it seems to only exist in FreeBSD, and regarding the
> -@@ -1250,23 +1268,36 @@ void engine_load_devcrypto_int()
> -  */
> - #if 0
> - # ifndef OPENSSL_NO_RSA
> --        || !ENGINE_set_RSA(e, devcrypto_rsa)
> ++/*
> ++ * Asymmetric ciphers aren't well supported with /dev/crypto.  Among the BSD
> ++ * implementations, it seems to only exist in FreeBSD, and regarding the
> ++ * parameters in its crypt_kop, the manual crypto(4) has this to say:
> ++ *
> ++ *    The semantics of these arguments are currently undocumented.
> ++ *
> ++ * Reading through the FreeBSD source code doesn't give much more than
> ++ * their CRK_MOD_EXP implementation for ubsec.
> ++ *
> ++ * It doesn't look much better with cryptodev-linux.  They have the crypt_kop
> ++ * structure as well as the command (CRK_*) in cryptodev.h, but no support
> ++ * seems to be implemented at all for the moment.
> ++ *
> ++ * At the time of writing, it seems impossible to write proper support for
> ++ * FreeBSD's asym features without some very deep knowledge and access to
> ++ * specific kernel modules.
> ++ *
> ++ * /Richard Levitte, 2017-05-11
> ++ */
> ++#if 0
> ++# ifndef OPENSSL_NO_RSA
>  +        && ENGINE_set_RSA(e, devcrypto_rsa)
> - # endif
> - # ifndef OPENSSL_NO_DSA
> --        || !ENGINE_set_DSA(e, devcrypto_dsa)
> ++# endif
> ++# ifndef OPENSSL_NO_DSA
>  +        && ENGINE_set_DSA(e, devcrypto_dsa)
> - # endif
> - # ifndef OPENSSL_NO_DH
> --        || !ENGINE_set_DH(e, devcrypto_dh)
> ++# endif
> ++# ifndef OPENSSL_NO_DH
>  +        && ENGINE_set_DH(e, devcrypto_dh)
> - # endif
> - # ifndef OPENSSL_NO_EC
> --        || !ENGINE_set_EC(e, devcrypto_ec)
> ++# endif
> ++# ifndef OPENSSL_NO_EC
>  +        && ENGINE_set_EC(e, devcrypto_ec)
> - # endif
> - #endif
> --        || !ENGINE_set_ciphers(e, devcrypto_ciphers)
> --#ifdef IMPLEMENT_DIGEST
> --        || !ENGINE_set_digests(e, devcrypto_digests)
> --#endif
> --        ) {
> ++# endif
> ++#endif
>  +        );
>  +}
>  +
> @@ -320,13 +2689,14 @@ index 2c1b52d572..eff1ed3a7d 100644
>  +    if ((e = ENGINE_new()) == NULL
>  +        || !bind_devcrypto(e)) {
>  +        close_devcrypto();
> -         ENGINE_free(e);
> -         return;
> -     }
> -@@ -1275,3 +1306,22 @@ void engine_load_devcrypto_int()
> -     ENGINE_free(e);          /* Loose our local reference */
> -     ERR_clear_error();
> - }
> ++        ENGINE_free(e);
> ++        return;
> ++    }
> ++
> ++    ENGINE_add(e);
> ++    ENGINE_free(e);          /* Loose our local reference */
> ++    ERR_clear_error();
> ++}
>  +
>  +#else
>  +
> diff --git a/package/libs/openssl/patches/500-e_devcrypto-default-to-not-use-digests-in-engine.patch b/package/libs/openssl/patches/500-e_devcrypto-default-to-not-use-digests-in-engine.patch
> index 1f1cd7a582..df5c16d8d2 100644
> --- a/package/libs/openssl/patches/500-e_devcrypto-default-to-not-use-digests-in-engine.patch
> +++ b/package/libs/openssl/patches/500-e_devcrypto-default-to-not-use-digests-in-engine.patch
> @@ -19,8 +19,6 @@ turn them on if it is safe and fast enough.
>
>  Signed-off-by: Eneas U de Queiroz <cote2004-github at yahoo.com>
>
> -diff --git a/engines/e_devcrypto.c b/engines/e_devcrypto.c
> -index 3fcd81de7a..d25230d366 100644
>  --- a/engines/e_devcrypto.c
>  +++ b/engines/e_devcrypto.c
>  @@ -852,7 +852,7 @@ static void prepare_digest_methods(void)
> @@ -32,7 +30,7 @@ index 3fcd81de7a..d25230d366 100644
>
>           /*
>            * Check that the digest is usable
> -@@ -1072,7 +1072,7 @@ static const ENGINE_CMD_DEFN devcrypto_cmds[] = {
> +@@ -1072,7 +1072,7 @@ static const ENGINE_CMD_DEFN devcrypto_c
>   #ifdef IMPLEMENT_DIGEST
>      {DEVCRYPTO_CMD_DIGESTS,
>       "DIGESTS",
> diff --git a/package/libs/openssl/patches/510-e_devcrypto-ignore-error-when-closing-session.patch b/package/libs/openssl/patches/510-e_devcrypto-ignore-error-when-closing-session.patch
> index bc514b88c9..87792cf9d0 100644
> --- a/package/libs/openssl/patches/510-e_devcrypto-ignore-error-when-closing-session.patch
> +++ b/package/libs/openssl/patches/510-e_devcrypto-ignore-error-when-closing-session.patch
> @@ -8,11 +8,9 @@ session.  It may have been closed by another process after a fork.
>
>  Signed-off-by: Eneas U de Queiroz <cote2004-github at yahoo.com>
>
> -diff --git a/engines/e_devcrypto.c b/engines/e_devcrypto.c
> -index d25230d366..f4570f1666 100644
>  --- a/engines/e_devcrypto.c
>  +++ b/engines/e_devcrypto.c
> -@@ -195,9 +195,8 @@ static int cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
> +@@ -195,9 +195,8 @@ static int cipher_init(EVP_CIPHER_CTX *c
>           get_cipher_data(EVP_CIPHER_CTX_nid(ctx));
>
>       /* cleanup a previous session */



More information about the openwrt-devel mailing list