如何确定openssl.cnf的默认位置?

时间:2016-05-04 18:27:44

标签: bash openssl

背景

我正在编写一个bash脚本,该脚本将使用openssl生成符合 X509v3扩展名主题备用名称的证书签名请求。

由于没有这样的命令行选项,a solution已将-config选项与-reqexts选项结合使用,方法是将SAN值内联到内联默认配置文件。

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

问题

我的问题是便携性。虽然a similar question向我保证这可以在我的Ubuntu环境中运行,因为默认配置文件是/etc/ssl/openssl.cnf,但不幸的是,这无处不在,Windows就是明显的例子。

如何以编程方式确定openssl 默认配置文件的完整路径?

我尝试过什么

documentation

中有一个明显的暗示
  

-config filename
  这允许指定备用配置文件,这将覆盖编译时文件名或OPENSSL_CONF环境变量中指定的任何文件。

我已经阅读了config documentation并搜索了source code,但我无法找到从哪里加载&#34;编译时间&#的机制34;默认配置文件。如果我能找到,那么我宁愿将其作为变量加载到脚本而不是硬编码路径中。

此外,我的$OPENSSL_CONF变量为空。

不良选择

目前我的脚本检查这些条件,并使用第一个评估为true的条件:

  1. $OPENSSL_CONF变量已填充,文件存在
  2. /etc/ssl/openssl.cnf存在
  3. 如果这些都不是真的,那么它包括标准配置的副本。这是不合需要的,因为它实际上会覆盖客户端建立的自定义设置。我想完全使用环境条件,只需添加SAN部分作为附录。

    我可以用通常的嫌疑人甚至系统搜索的路径进一步扩展这个链。但是如果存在多个,那么我无法保证openssl实际上将其用作默认值。

2 个答案:

答案 0 :(得分:8)

  

如何以编程方式确定openssl默认配置文件的完整路径?

以编程方式,它就像使用OPENSSLDIR中的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"
  

如何确定openssl.cnf的默认位置?

这里有更多信息可以帮助填补其他Stack Overflow问题的空白。这取决于您使用的OpenSSL安装。

这是简短的答案......图书馆和程序会在openssl.cnf中查找OPENSSLDIROPENSSLDIR是一个配置选项,其设置为--openssldir

我在MacBook上有3种不同的OpenSSL(Apple,MacPort和我建的):

# 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"

这是更长的答案......它隐藏在apps.cload_config的OpenSSL源代码中,以及当cnfNULL时会发生什么(即没有-config选项或OPENSSL_CONF envar)。如果cnfNULL且未覆盖,则使用OPENSSLDIR

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;
}
  

...这在我的Ubuntu环境中有效,因为默认配置文件是/etc/ssl/openssl.cnf,遗憾的是这在任何地方都不起作用,Windows就是一个明显的例子。

在Windows上,这可能仍然是一个问题。如果您自己从源代码构建OpenSSL,那么您应该没问题;在Windows中模拟它们的长文件名处理(另见Issue #4490: "nmake install" fails "Destination must be a directory at .\util\copy.pl line 39" on)。

Shinning Light and Win32 OpenSSL这样的人提供安装程序,并且OpenSSL 可能不会安装在打包程序所设想的目录中。我甚至看到像/usr/local这样的Unix目录出现在Windows机器上。

对于Windows,您最安全的选择可能是设置OPENSSL_CONF环境变量来覆盖损坏的路径和路径处理错误。

另外,我不知道CONF_*NCONF_* API调用会在运行时为您提供有效的目录。这里,有效目录将是配置目录以及OPENSSL_CONF覆盖之类的内容。现在在OpenSSL用户列表中打开:Get effective OPENSSLDIR path at runtime?

答案 1 :(得分:4)

如评论之一所述,简单的答案应该是使用以下命令找到路径:

openssl version -d

如果这不起作用,则可以假定未正确配置OpenSSL,或者至少没有所需的配置。这是Node.js中有关如何获取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);
})();