On Mon, Jan 26, 2026 at 05:32:44PM -0500, Ken Goldman wrote:
> > The problem at hand is how to **CONFIGURE** use of a particular FIPS
> > module, whether it is installed in the same directory tree as the
> > OpenSSL runtime to which the application is linked, or not.
>
> Specifically, configure an application to link to my
> local openssl build.
No, you're confused. You don't **link** applications against the FIPS
provider, the provider is dynamically loaded (at runtime, not link
time). This applies equally to:
- The openssl(1) command-line utility and its various subcommands,
such as openssl-s_client(1), ...
- Existing applications that use an OpenSSL 3.x (or development 4.x
snapshot) library.
- Any "toy" applications you want to test.
All the above can be compiled against the headers in
/usr/include/ and linked with the system OpenSSL runtime in
/usr/lib (or /usr/lib64 depending on the OS). As already
explained, what makes them use the FIPS provider is the
CONFIGURATION file.
To test a non-default configuration (i.e. not make system-wide changes
as root), you set the OPENSSL_CONF environment variable to point at a
test configuration file in some directory that also contains the
"fipsmodule.cnf" file. The test directory structure is then something
like:
/some/where/ssl/openssl.cnf
/some/where/ssl/fipsmodule.cnf
/some/where/lib/ossl-modules/fips.so
The "fipsmodule.cnf" file is machine-generated by either the
"openssl fipsinstall" command as in the posted shell script,
or by running "make install_fips" (after a suitable choice
of "--prefix=..." when configuring the build).
You can in principle also obtain and install a pre-compiled "fips.so"
and a corresponding "fipsmodule.cnf" from a suitably reputable software
vendor. Building your own is not a requirement.
and you then adjust the "openssl.cnf" file to your liking and:
$ export OPENSSL_CONF=/some/where/ssl/openssl.cnf
$ export OPENSSL_CONF_INCLUDE=/some/where/ssl
$ export OPENSSL_MODULES=/some/where/lib/ossl-modules
... run whatever tests you want ...
> > That requires making sure that the application's "openssl.cnf" file (or
> > whatever path the OPENSSL_CONF environment variable takes) contains
> > settings that load the "fips" and "default" providers (or in some cases
> > just "fips" and "base"). And making sure that the "fips" module is
> > properly installed with a matching "fipsmodule.cnf" found in
> > $OPENSSL_CONF_INCLUDE (if a relative file name and not in the default
> > location).
>
> Is there more specific documentation?
I posted a shell script that does all the work, and a followup message
with manpage references if you'd like to read more, there is no
additional documentation needed in order to run tests. When I run
the script the directory ended up containing:
/tmp/ossl-test-dir.GOT9Fh/lib/ossl-modules/fips.so
/tmp/ossl-test-dir.GOT9Fh/ssl/openssl.cnf
/tmp/ossl-test-dir.GOT9Fh/ssl/fipsmodule.cnf
And the configuration was (verbatim):
openssl_conf = openssl_init
config_diagnostics = 1
.include fipsmodule.cnf
[openssl_init]
providers = provider_sect
alg_section = evp_properties
[evp_properties]
default_properties = "fips=yes"
[provider_sect]
fips = fips_sect
base = base_sect
[base_sect]
activate = 1
With those environment variables, that pair of configuration
files and the compiled module,
> Perhaps I should copy openssl.cnf to my application directory? And set
> OPENSSL_CONF to its location?
Yes, or any other location of your choice, where you'd also install the
"fipsmodule.cnf" file, and the "fips.so" dynamic shared object in a
related or even the same directory.
> There is a fips section. Must I edit it?
Exactly as shown above. The critical section is the unnamed
"default section" at the top of the file. This specifies
an "openssl_conf" parameter that names some section of your
choice:
# Any RHS section name will do
openssl_conf = larry-conf-42
# Required for FIPS
.include fipsmodule.cnf
[larry-conf-42]
providers = curly-providers-1729
alg_section = moe-evp-631
[curly-providers-1729]
# This has to match the "fipsmodule.cnf" file
fips = fips_sect
# With just "fips" and "base" this is a "FIPS-only" combination
base = groucho-432423
# You might instead
# want a "FIPS + default" combination, comment out "base"
# above and uncomment "default" below:
# default = groucho-432423
[moe-evp-631]
# Comment out if non-FIPS algorithms should also be available.
default_properties = "fips=yes"
[groucho-432423]
activate = 1
The names on the left of the "=" signs are compiled-in literals, you
have use these unchanged. The section names on the right are yours to
choose, but try to not make them silly like above.
> Should I copy providers/fipsmodule.cnf somewhere, perhaps a providers
> subdirectory? And edit it or not?
The "fipsmodule.cnf" file is machine-generated and critical for the
module to pass integrity checks during "power-on-self-test" (POST).
You SHOULD NOT edit it if you want the module to work.
> Where would fips.so go?
Anywhere you want. The directory that contains it is specified
via the "OPENSSL_MODULES" environment variable (otherwise it
is whatever is whatever is reported by "openssl version -m",
for example with Fedora 43:
$ /usr/bin/openssl version -m
MODULESDIR: "/usr/lib64/ossl-modules"
> Do I link to it, or is there a runtime link based on the configuration
> files?
In this and in more than one upthread post, which I'd like to recommend
you read closely, I've made it quite clear that you DO NOT link your
code against the FIPS module, it is loaded at runtime if the
configuration specifies "fips" as one of the "providers" to "activate".
> Perhaps I don't have to copy anything but just set several env
> variables?
You can indeed use everything directly from the build tree if you wish,
in which case:
export OPENSSL_MODULES=$PWD/providers
export OPENSSL_CONF_INCLUDE=$PWD/providers
export OPENSSL_CONF=$PWD/test/fips-and-base.cnf
or instead:
export OPENSSL_CONF=$PWD/test/default-and-fips.cnf
depending on whether you want you want a FIPS-only, or
a fips-optional configuration. The below may be
helpful:
$ diff -U1 <(grep -v '^#' test/default-and-fips.cnf) \
<(grep -v '^#' test/fips-and-base.cnf)
--- /dev/fd/63 2026-01-27 12:02:49.636190765 +1100
+++ /dev/fd/62 2026-01-27 12:02:49.637190768 +1100
@@ -9,7 +9,10 @@
+[evp_properties]
+default_properties = "fips=yes"
+
[provider_sect]
-default = default_sect
fips = fips_sect
+base = base_sect
-[default_sect]
-activate = yes
+[base_sect]
+activate = 1
> > Therefore, what Ken needs to know (even if perhaps he did not know to
> > ask) is how use a specific FIPS module. He almost certainly already
> > knows how to link applications against a specific OpenSSL runtime, and
> > even with both FIPS and OpenSSL from a single build, one still needs to
> > apply the appropriate configuration settings.
>
> I know how to link to a local libcrypto.so, but not how to link to a local
> fips.so.
That's because the latter is not a matter of "linking", as noted.
> > Some relevant additional manpages are:
> >
> > openssl-fipsinstall(1)
> > fips_config(5)
> > fips_module(7)
> >
> > basic installation of the "fips.so" and "fipsmodule.cnf"
> > can be accomplished via "make install_fips".
>
> I don't want to install (or do anything as root), just
> link and run against a local build (not in any system area).
I did not suggest any steps that require "root" privileges or modify the
ambient OS environment outside your test runs.
My recommendation is to copy ("install" as a non-root user) the
requisite files to a dedicated private filesystem tree outside the build
directory. This decouples your tests from the OpenSSL build, you can
test any version (or multiple versions) of the module, and gives an
indication of how you'd actually deploy the module for live use.
As noted above, if you want to skip all of that, you can use the
files in directly out of the build tree:
$ export OPENSSL_MODULES=$PWD/providers
$ export OPENSSL_CONF_INCLUDE=$PWD/providers
$ export OPENSSL_CONF=$PWD/test/fips-and-base.cnf
... run your tests ...
$ export OPENSSL_MODULES=$PWD/providers
$ export OPENSSL_CONF_INCLUDE=$PWD/providers
$ export OPENSSL_CONF=$PWD/test/default-and-fips.cnf
... run your tests ...
The latter exposes both FIPS and non-FIPS algorithms, the application
can then selectively use a "property string" (propq) of "fips=yes" when
desired, and otherwise still use non-FIPS algorithms.
An example from the build tree:
$ fipsrun() { (
export LD_LIBRARY_PATH=$PWD \
OPENSSL_CONF=$1 \
OPENSSL_CONF_INCLUDE=$PWD/providers \
OPENSSL_MODULES=$PWD/providers
shift
./apps/openssl "$@"
); }
$ fipsrun test/default-and-fips.cnf list -digest-algorithms | wc -l
103
# The FIPS module does include some non-validated algorithms,
# visible unless the property string is set to "fips=yes".
#
$ fipsrun test/fips-and-base.cnf list -digest-algorithms | wc -l
75
Finally, with "fips=yes", just the FIPS validated algorithms:
$ fipsrun test/fips-and-base.cnf list -digest-algorithms -propquery='"fips=yes"'
Provided:
{ 2.16.840.1.101.3.4.2.10, SHA3-512 } @ fips
{ 2.16.840.1.101.3.4.2.6, SHA-512/256, SHA2-512/256, SHA512-256 } @ fips
{ 2.16.840.1.101.3.4.2.4, SHA-224, SHA2-224, SHA224 } @ fips
{ 1.3.14.3.2.26, SHA-1, SHA1, SSL3-SHA1 } @ fips
{ 2.16.840.1.101.3.4.2.7, SHA3-224 } @ fips
{ 2.16.840.1.101.3.4.2.9, SHA3-384 } @ fips
{ 2.16.840.1.101.3.4.2.3, SHA-512, SHA2-512, SHA512 } @ fips
{ 2.16.840.1.101.3.4.2.5, SHA-512/224, SHA2-512/224, SHA512-224 } @ fips
{ 2.16.840.1.101.3.4.2.12, SHAKE-256, SHAKE256 } @ fips
{ 2.16.840.1.101.3.4.2.2, SHA-384, SHA2-384, SHA384 } @ fips
{ 2.16.840.1.101.3.4.2.8, SHA3-256 } @ fips
{ 2.16.840.1.101.3.4.2.1, SHA-256, SHA2-256, SHA256 } @ fips
{ 2.16.840.1.101.3.4.2.11, SHAKE-128, SHAKE128 } @ fips
ML-DSA-MU @ fips
--
Viktor. 🇺🇦 Слава Україні!