I'm writing a bash script that will use openssl to generate a certificate signing request with X509v3 extension compliant subject alternative names.
Since there's no command line option for this, a solution has been to use the -config
option in conjunction with the -reqexts
option by appending the SAN values inline to the default configuration file.
openssl req -new -sha256 -key domain.key -subj "/C=US/ST=CA/O=Acme, Inc./CN=example.com" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:example.com,DNS:www.example.com")) -out domain.csr
My problem is portability. While a similar question assures me that 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.
How do I programmatically determine the full path to the openssl default configuration file?
There's a glaring hint in the documentation
-config filename
this allows an alternative configuration file to be specified, this overrides the compile time filename or any specified in the OPENSSL_CONF environment variable.
I've read the config documentation and searched the source code, but I can't discover the mechanism by which it chooses from where to load the "compile time" default config file. If I could find that, then I would prefer to load it as a variable into the script instead of the hard-coded path.
Moreover, my $OPENSSL_CONF
variable is empty.
Currently my script checks these conditions, and uses the first one that evaluates to true:
$OPENSSL_CONF
variable is populated, and file exists/etc/ssl/openssl.cnf
existsIf neither of those are true, then it includes a copy of a standard configuration. This is undesirable because it would in effect override custom settings established by the client. I want to use the environment's conditions completely, and simply add the SAN section as an addendum.
I could further extend this chain with the paths of the usual suspects or even a system search. But in the event that multiple exist, then I have no assurance of which is in fact used by openssl as a default.
OpenSSL by default looks for a configuration file in /usr/lib/ssl/openssl. cnf so always add -config /etc/openssl. cnf to the commands openssl ca or openssl req for instance.
OpenSSL for Windows has now been installed and can be found as OpenSSL.exe in C:\OpenSSL-Win32\bin\.
The openssl. cnf file is primarily used to set default values for the CA function, key sizes for generating new key pairs, and similar configuration. Consult the OpenSSL documentation available at openssl.org for more information.
cnf is the "official" copy of the file. /private/etc/ssl/openssl. cnf is a private copy of the file for some software on the system which needs its own copy. /System/Library/Templates/Data/private/etc/ssl/openssl.
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); })();
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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With