Build and Test a Safe OpenSSL Configuration File

An OpenSSL config file will quietly load an included fragment or swap a provider with no warning, and you only notice once a handshake fails. This guide builds a small configuration in a throwaway directory, using sections, variables and an include, then proves it is actually being read. The workflow leaves the system OpenSSL configuration untouched. Allow about 15 minutes. You need a shell, OpenSSL, and permission to write in a temporary directory. The examples use the local config(5ssl) manual, generated for OpenSSL 3.0.13, while the executable available on this machine reports OpenSSL 3.6.1. Check your own version before relying on version-specific behaviour.

1. Check which OpenSSL you will test

Run these commands as your ordinary user:

$ command -v openssl
/home/linuxbrew/.linuxbrew/bin/openssl
$ openssl version
OpenSSL 3.6.1 27 Jan 2026

Your path and version may differ. Keep the distinction clear: config(5ssl) describes the configuration syntax and the library modules, but a different OpenSSL executable might load a different default configuration directory. The rest of this guide passes OPENSSL_CONF explicitly, so it does not depend on that default.

2. Make an isolated configuration directory

Create a temporary directory and two files. The first file contains the default section and a named section. The second file is included from it.

$ workdir=$(mktemp -d)
$ chmod 700 "$workdir"
$ printf '%s\n' 'temporary configuration directory: '"$workdir"

Do not put secrets in a test configuration. OpenSSL configuration values can be exposed by debugging, process setup, or careless file permissions. The chmod protects this directory while you work.

Create the included file:

$ cat > "$workdir/extra.cnf" <<'EOF'
[extra]
message = loaded from the included file
EOF

Here, cat is only writing the explicitly named temporary file. If you prefer an editor, create the same two-line content at $workdir/extra.cnf.

3. Use the configuration syntax

Now create the main file:

$ cat > "$workdir/main.cnf" <<EOF
# The unnamed opening section is the default section.
configdir = $workdir
openssl_conf = openssl_init
.include $workdir/extra.cnf

[openssl_init]
oid_section = oids

[oids]
demo_oid = 1.2.3.4.1
EOF

A configuration is made of sections and name/value assignments. The opening lines form the default section until [openssl_init]. openssl_conf tells the library which section describes module initialisation. The OID section adds a name that OpenSSL can use when it parses an object identifier. The include is processed at that point, so the extra section becomes available to the same configuration.

Values are expanded when they are read. The shell expands $workdir while the here document is created, producing an absolute include path. This is deliberate: the manual recommends absolute paths, and an absolute path avoids surprises from the current working directory or from OPENSSL_CONF_INCLUDE.

Checkpoint: inspect the two files without loading them into a privileged service:

$ sed -n '1,80p' "$workdir/main.cnf"
$ sed -n '1,40p' "$workdir/extra.cnf"

4. Prove that the file is being read

Use the temporary file for one command by setting OPENSSL_CONF on that command only:

$ OPENSSL_CONF="$workdir/main.cnf" openssl asn1parse -genstr OID:1.2.3.4.1
0:d=0  hl=2 l=   4 prim: OBJECT            :demo_oid

The exact spacing can vary, but the final name should be demo_oid. That is the useful verification: the command recognised the OID declared in your file. This command reads configuration and prints an object identifier. It does not write a certificate, alter a provider, or modify the system configuration.

If the name is not shown, check the path and the file contents first. An unset or empty OPENSSL_CONF has different meaning from a path: the manual documents the empty string as disabling configuration loading. Do not troubleshoot by editing /etc/ssl or another system directory.

5. Make relative includes predictable

Relative includes are allowed by default, but they depend on include-directory rules and the current environment. You can require absolute include paths by adding this line near the start of the main file:

.pragma abspath:on

With that pragma, an include such as .include extra.cnf is rejected because it is not absolute. The OPENSSL_CONF_INCLUDE environment variable can prepend a directory to relative include paths, and the includedir pragma supplies another fallback. Those mechanisms are useful for a deliberately managed configuration tree, but they also make a copied file depend on its environment. For a small deployment file, explicit absolute paths are easier to review.

Directory includes have their own boundary: only files ending in .cnf or .conf are included, and subdirectories are ignored. Treat every included file as trusted configuration. An include can load providers or engines, and those modules may change which cryptographic implementations are available.

6. Turn on diagnostics only when you need them

Add config_diagnostics = 1 in the default section while investigating a broken module configuration:

config_diagnostics = 1

This makes configuration errors fail loudly instead of allowing an application to continue without the requested configuration. That is useful during testing, but it can also prevent access to a service when a configuration error reaches production. Remove it or make the operational choice deliberately after testing.

Never enable a provider or engine merely to make an example look complete. If a provider section explicitly activates a non-default provider, the default or FIPS provider may need explicit activation as well. Otherwise algorithms expected by openssl can become unavailable. Loading a module is a security-sensitive change, so test it with the exact application and package policy that will use it.

7. Clean up the test safely

The test files contain no useful state once the verification succeeds. Remove only the directory printed by your own shell:

$ rm -rf -- "$workdir"
$ test ! -e "$workdir" && echo 'temporary configuration removed'
temporary configuration removed

This is the only destructive command in the guide. Do not substitute /etc/ssl, your home directory, or an unresolved variable. If you need to preserve the example for review, skip the removal and delete that exact temporary directory later.

Done means