Home / Alt manpages / openssl-engine(1ssl)

  • openssl-engine(1ssl)
  • OpenSSL command
  • linux

Inspect OpenSSL Engines Safely Before Migrating to Providers

You will use openssl engine to identify legacy engines, inspect their capabilities, test whether one is available, and collect a useful failure trace without changing OpenSSL configuration. The command is deprecated in OpenSSL 3.0 and later, so this is an inspection and compatibility workflow, not a recommendation to build a new system around engines.

Allow about fifteen minutes. You need a shell and the OpenSSL command-line package. The examples were checked with OpenSSL 3.6.1 on Linux. Your engine list and paths will differ. None of the commands below needs elevated privileges when the OpenSSL installation and engine directory are readable by your user.

1. Check the installed OpenSSL command

Start by confirming which binary is being used and recording its version:

$ command -v openssl
/home/linuxbrew/.linuxbrew/bin/openssl
$ openssl version -a
OpenSSL 3.6.1 27 Jan 2026 (Library: OpenSSL 3.6.1 27 Jan 2026)
...

The version matters. The installed manual describes the command as deprecated since OpenSSL 3.0 and says that providers should be used instead. Keep that boundary in mind when reading an engine result: a successful query shows what the legacy interface can see, not that an application is using the provider model.

Checkpoint: if command -v finds a different binary from the one used by your service, stop and inspect the service environment before drawing conclusions. Shell aliases, containers and separate OpenSSL installations can expose different engine directories.

2. List the engines visible to this installation

With no engine name, the command lists the engines that the installation makes available by default:

$ openssl engine
(rdrand) Intel RDRAND engine
(dynamic) Dynamic engine loading support

This is an ordinary read-only query. An engine identifier such as rdrand is not a file name and is not necessarily present on another host. The dynamic entry is a loader for a separately supplied engine shared library; seeing it does not mean that a driver has been loaded.

To list the capabilities of the engines named by the command, use -c:

$ openssl engine -c
(rdrand) Intel RDRAND engine
 [RAND]
(dynamic) Dynamic engine loading support

The capability line is the useful part of this output. For example, [RAND] says that the listed engine advertises a random-number capability. It does not prove that an application has selected the engine for all random-number operations.

3. Test an engine without loading a custom library

Use -t to ask whether a named engine is available:

$ openssl engine -t rdrand
(rdrand) Intel RDRAND engine
     [ available ]

The exact wording can vary by OpenSSL build, but look for the availability result and the command's exit status:

$ openssl engine -t rdrand >engine-test.txt
$ status=$?
$ printf 'openssl engine exit status: %s
' "$status"
openssl engine exit status: 0

Writing the output to a temporary file makes it harder to lose the status while scrolling through diagnostics. Remove engine-test.txt after inspection if it contains nothing you need. Do not use sudo merely to query an engine. If an engine is available only to a service account, reproduce the service account's environment instead of widening permissions.

4. Get an error trace for an unavailable engine

When availability fails, add -tt. This asks OpenSSL to display an error trace for an unavailable engine:

$ openssl engine -t -tt does-not-exist
$ printf 'exit status: %s\n' "$?"
exit status: 1

The command writes a build-specific error trace to standard error, including the engine directory and the reason the shared object could not be loaded. Do not script against the punctuation or process-specific details. Script against the non-zero exit status and retain the complete diagnostic for the operator. A made-up identifier is a safe way to check your error-handling path because it does not load a shared library.

Common causes include a misspelled engine identifier, an engine that is not installed for this OpenSSL build, an incompatible shared library, or a library that cannot be read. Check the selected binary and its environment before changing files:

$ openssl version -e
ENGINESDIR: "/home/linuxbrew/.linuxbrew/Cellar/openssl@3/3.6.1/lib/engines-3"
$ printf 'OPENSSL_ENGINES=%s
' "${OPENSSL_ENGINES-unset}"
OPENSSL_ENGINES=unset

OPENSSL_ENGINES names the engines directory. If it is set, an inherited value can point at a directory belonging to another OpenSSL installation. Verify the directory and library ownership before changing the variable. Do not delete or replace an engine library as a first troubleshooting step.

5. Inspect control commands with increasing detail

The -v family describes the run-time controls exposed by a specified engine. Each additional v adds another layer of detail:

  • -v lists control commands.
  • -vv adds descriptions.
  • -vvv adds input flags.
  • -vvvv also shows internal input flags.

For the built-in dynamic loader, the most useful first inspection is:

$ openssl engine -vvvv dynamic
(dynamic) Dynamic engine loading support
     SO_PATH: Specifies the path to the new ENGINE shared library
          (input flags): STRING
     NO_VCHECK: Specifies to continue even if version checking fails (boolean)
          (input flags): NUMERIC
     ID: Specifies an ENGINE id name for loading
          (input flags): STRING
     LIST_ADD: Whether to add a loaded ENGINE to the internal list (0=no,1=yes,2=mandatory)
          (input flags): NUMERIC
     DIR_LOAD: Specifies whether to load from 'DIR_ADD' directories (0=no,1=yes,2=mandatory)
          (input flags): NUMERIC
     DIR_ADD: Adds a directory from which ENGINEs can be loaded
          (input flags): STRING
     LOAD: Load up the ENGINE specified by other settings
          (input flags): NO_INPUT

This output is a description of the loader's interface. It is not a request to load a library. Keep the inspection command separate from any command that supplies -pre or -post values.

6. Treat dynamic loading as a security boundary

-pre sends a cmd:val control command before an engine is loaded, while -post sends one after loading. These options are cumulative. A typical dynamic-engine sequence would provide a trusted shared-library path, an identifier and the LOAD command:

$ openssl engine -t -tt \
    -pre SO_PATH:/trusted/path/libexample-engine.so \
    -pre ID:example \
    -pre LOAD \
    dynamic

Do not run that example with a guessed or untrusted path. Loading a shared library executes code in the OpenSSL process, and an engine may access sensitive cryptographic operations. This is the point where a harmless query becomes a security-sensitive action. Confirm the library's provenance, permissions, ABI compatibility and intended service account first. If you do load one and it fails, remove no files: return to -t -tt, check the trace, and restore the service's previous configuration if you changed it.

For new integrations, ask whether the required functionality is available as an OpenSSL provider. Providers are the supported OpenSSL 3 architecture; the engine command remains useful when auditing an older deployment or diagnosing a compatibility dependency.

Done means

  • You recorded the exact OpenSSL binary and version under test.
  • You listed visible engines and inspected capabilities without changing configuration.
  • You used -t for availability and -tt for a failure trace.
  • You checked OPENSSL_ENGINES and the engine directory before troubleshooting paths.
  • You treated -pre, -post and dynamic shared-library loading as security-sensitive.
  • You know that engines are deprecated in OpenSSL 3 and that providers are the migration target.