openssl: Cannot dynamically load FIPS module from alternate location

This issue deals with the exact problem from ticket #17301 but is larger than that issue since I have duplicated the problem on both Windows and Android.

Basically, I want to load the OpenSLL FIPS module when the executable and config files are not in the standard location simply by dynamically loading the library and making function calls. My end-use case is on Android but when I couldn’t get it to work on Android, I switched to trying the same thing on Windows since I personally find it much easier to debug on Windows.

I built v3.0.4 for 64-bit Windows. I specified --prefix and --openssldir when I configured since I don’t want them put in the usual place. This is a very minimal build since all I want is FIPS crypto without any extra algorithms or any SSL / TLS support. The install_fips portion of “nmake install” did successfully run and created the .cnf file with the module-mac data.

I copied libcrypto-3-x64.dll, fips.dll and myconfig.cnf to a test directory location. My config file is (told you it was a minimal build / use):

[openssl_init]
providers = provider_sect

[provider_sect]
fips = fips_sect

[fips_sect]
conditional-errors = 1
security-checks = 1
module-mac = <<<value copied from the cnf file created during fips install>>>

I created a console application to load the FIPS module. It is linked so that libcrypto is delay loaded, and I have verified that it is delay loaded (see my breakpoint discussion below). Here’s my code:

SetEnvironmentVariable ("OPENSSL_CONF", "e:\\temp\\testloc\\myconfig.cnf");
SetEnvironmentVariable ("OPENSSL_MODULES", "e:\\temp\\testloc");
... print out environ vars and verify they are set to the above

LoadLibrary ("e:\\temp\\testloc\\libcrypto-3-x64.dll");

OSSL_LIB_CTX* fipsLibCtx = OSSL_LIB_CTX_new ();
... error check

OSSL_PROVIDER_set_default_search_path (fipsLibCtx, "e:\\temp\\testloc");
... error check

OSSL_LIB_CTX_load_config (fipsLibCtx, "e:\\temp\\testloc\\myconfig.cnf");
... error check

OSSL_PROVIDER* fipsProv = OSSL_PROVIDER_load (fipsibCtx, "fips");

the last line fails and the errors from ERR_print_errors are:

E4E0000:error:1C8000D5:Provider routines:SELF_TEST_post:missing config data::0:
E4E0000:error:1C8000E0:Provider routines:ossl_set_error_state:fips module entering error state::0:
E4E0000:error:1C8000D8:Provider routines:OSSL_provider_init_int:self test post failure::0:
E4E0000:error:078C0105:common libcrypto routines:provider_init:init fail::0:name=fips

Note - I have tried this with activate = 1 in the cnf file and the behavior is identical.

I have the following breakpoints set when I run this code:

  1. first line of CONF_get1_default_config_file – this is the ONLY place in the source code that I could find that uses the OPENSSL_CONF environment variable and this break point is never hit – where is the fips self-test getting its verification data from?

  2. DllMain for both libcrypto and fips – libcrypto bp is hit during the execution of LoadLibrary and fips bp is hit during OSS_PROVIDER_load

  3. call to fips_get_params_from_core in OSSL_provider_init_int – bp is hit and the call succeeds, so it thinks it has read the parameters successfully

  4. both lines in SELF_TEST_post that can return PROV_R_MISSING_CONFIG_DATA – the first bp is hit indicating that module_checksum_data is NULL

As far as I can tell, the issue is that my .cnf file is never read in and therefore the verification data is never set for the self test.

I can’t duplicate setting breakpoints in libcrypto when running this on Android but it fails at OSSL_PROVIDER_load with the exact same error messages, so this isn’t OS specific. The Android C code is exactly the same (using android/linux calls for environment variables and library load) and uses the location “/data/user/0/com.example.myapp/files” which is my app’s private file area.

So, my issue is … what am I missing to force it to find that config file?

Thanks, Judy

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 16 (6 by maintainers)

Most upvoted comments

Yes, it works on Android. In my final version, I also needed the base provider so that is now included.

My config and SO are located in the files directory of my app. I get that path at the Java level by activity.getFilesDir().getAbsolutePath() I then pass that directory down to native code to do the OpenSSL init.

config file is:

openssl_conf = openssl_init

[openssl_init]
providers = provider_sect

[provider_sect]
fips = fips_sect
base = base_sect

[fips_sect]
conditional-errors = 1
security-checks = 1
module-mac = <<<value copied from the cnf file created during fips install>>>

[base_sect]

startup code (error checking removed):

void* cryptoModule;
OSSL_PROVIDER* fipsProv;
OSSL_PROVIDER* baseProv;

void init (const char* filesDir)
{
    char fullConfigName[300];
    strcpy (fullConfigName, filesDir);
    strcat (fullConfigName, "/myconfig.cnf");

    char fullSoName[300];
    strcpy (fullSoName, filesDir);
    strcat (fullSoName, "/cryptolib.so");          // whatever the exact name of the SO is

    setenv ("OPENSSL_CONF", fullConfigName, 1);
    setenv ("OPENSSL_MODULES", fileDir, 1);

    cryptoModule = dlopen (fullSoName, RTLD_LAZY);
    OSSL_PROVIDER_set_default_search_path (NULL, filesDir);
    OSSL_LIB_CTX_load_config (NULL, fullConfigName);

    fipsProv = OSSL_PROVIDER_load (NULL, "fips");
    baseProv = OSSL_PROVIDER_load (NULL, "base");
}

Since this is a dynamic load of the fips library, I have to do a dlsym lookup for each of the OSSL_xxx functions and then call through the returned function pointer.