How to determine the default location for openssl.cnf?

How do I programmatically determine the full path to the openssl default configuration file?

Programmatically, its as easy as using the OPENSSLDIR macro from opensslconf.h:

$ cat /usr/local/ssl/darwin/include/openssl/opensslconf.h | grep OPENSSLDIR
#if defined(HEADER_CRYPTLIB_H) && !defined(OPENSSLDIR)
#define OPENSSLDIR "/usr/local/ssl/darwin"

How to determine the default location for openssl.cnf?

Here's more information to help fill in the gaps from the other Stack Overflow question. It depends on the OpenSSL installation you are using.

Here's the short answer... The library and programs look for openssl.cnf in OPENSSLDIR. OPENSSLDIR is a configure option, and its set with --openssldir.

I'm on a MacBook with 3 different OpenSSL's (Apple's, MacPort's and the one I build):

# Apple    
$ /usr/bin/openssl version -a | grep OPENSSLDIR
OPENSSLDIR: "/System/Library/OpenSSL"

# MacPorts
$ /opt/local/bin/openssl version -a | grep OPENSSLDIR
OPENSSLDIR: "/opt/local/etc/openssl"

# My build of OpenSSL
$ openssl version -a | grep OPENSSLDIR
OPENSSLDIR: "/usr/local/ssl/darwin"

Here's the longer answer... It is kind of buried in OpenSSL source code for apps.c, load_config and what happens when cnf is NULL (i.e., no -config option or OPENSSL_CONF envar). When cnf is NULL and no overrides, then OPENSSLDIR is used.

int load_config(BIO *err, CONF *cnf)
{
    static int load_config_called = 0;
    if (load_config_called)
        return 1;
    load_config_called = 1;
    if (!cnf)
        cnf = config;
    if (!cnf)
        return 1;

    OPENSSL_load_builtin_modules();

    if (CONF_modules_load(cnf, NULL, 0) <= 0) {
        BIO_printf(err, "Error configuring OpenSSL\n");
        ERR_print_errors(err);
        return 0;
    }
    return 1;
}

... this works in my Ubuntu environment because the default configuration file is /etc/ssl/openssl.cnf, unfortunately this won't work everywhere, with Windows being the obvious example.

This may still be a problem for you on Windows. You should be OK if you build OpenSSL from sources yourself; modulo their long filename handling in Windows (also see Issue #4490: "nmake install" fails "Destination must be a directory at .\util\copy.pl line 39" on).

Folks like Shinning Light and Win32 OpenSSL provide installers, and OpenSSL may not be installed in the directory the packager envisioned. I've even seen Unix directories like /usr/local appear on Windows machines.

For Windows, your safest bet is probably set the OPENSSL_CONF environmental variable to override broken paths and path handling bugs.


Also, I'm not aware of a CONF_* or NCONF_* API call that gives you the effective directory at runtime. Here, the effective directory would be the configuration directory plus things like OPENSSL_CONF overrides. Now open on the OpenSSL User list: Get effective OPENSSLDIR path at runtime?


As mentioned in one of the comments, the easy answer should be to find the path using the following command:

openssl version -d

If this doesn't work, you could presume that OpenSSL is not correctly configured, or at least doesn't have the configuration you need. Here is an example in Node.js on how you could get the location of openssl.cnf:

const util = require('util');
const path = require('path');
const exec = util.promisify(require('child_process').exec);

(async () => {
    const opensslCnfPath = path.normalize(`${(await exec('openssl version -d')).stdout.match(/"(.*)"/).pop()}/openssl.cnf`);
    console.log(opensslCnfPath);
})();

Tags:

Bash

Openssl