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

Jef*_*ett 14 bash openssl

背景

我正在编写一个bash脚本,它将使用openssl生成一个证书签名请求,其中包含符合X509v3扩展名的主题替代名称.

由于没有针对此的命令行选项,因此解决方案是将该-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
Run Code Online (Sandbox Code Playgroud)

我的问题是可移植性.虽然类似的问题向我保证这可以在我的Ubuntu环境中工作,因为默认的配置文件很/etc/ssl/openssl.cnf遗憾,这在任何地方都无法使用,Windows就是一个明显的例子.

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

我试过的

文档中有一个明显的暗示

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

我已经阅读了配置文档并搜索了源代码,但是我无法找到它从何处加载"编译时"默认配置文件的机制.如果我能找到它,那么我宁愿将其作为变量加载到脚本而不是硬编码路径中.

而且,我的$OPENSSL_CONF变量是空的.

一个不好的选择

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

  1. $OPENSSL_CONF 变量已填充,文件存在
  2. /etc/ssl/openssl.cnf 存在

如果这些都不是真的,那么它包括标准配置的副本.这是不合需要的,因为它实际上会覆盖客户端建立的自定义设置.我想完全使用环境条件,只需添加SAN部分作为附录.

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

jww*_*jww 9

如何以编程方式确定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"
Run Code Online (Sandbox Code Playgroud)

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

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

以下是简短的答案...图书馆和计划寻找openssl.cnfOPENSSLDIR.OPENSSLDIR是一个配置选项,其设置为--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"
Run Code Online (Sandbox Code Playgroud)

这里的较长答案......这是一种埋在OpenSSL的源代码apps.c,load_config会发生什么时,cnfNULL(即没有-config选项或OPENSSL_CONFENVAR).如果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;
}
Run Code Online (Sandbox Code Playgroud)

...这在我的Ubuntu环境中有效,因为默认的配置文件是/etc/ssl/openssl.cnf不可能的,因为Windows就是一个明显的例子.

在Windows上,这可能仍然是一个问题.如果你自己从源代码构建OpenSSL,你应该没问题.模块化他们在Windows中的长文件名处理(参见问题#4490:"nmake install"失败"目标必须是.\ util\copy.pl第39行的目录").

Shinning Light和Win32 OpenSSL这样的人提供了安装程序,OpenSSL 可能没有安装在打包器所设想的目录中.我甚至看到过像/usr/localWindows机器上出现的Unix目录.

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


另外,我不知道在运行时为您提供有效目录的API CONF_*NCONF_*API调用.这里,有效目录将是配置目录以及诸如OPENSSL_CONF覆盖之类的内容.现在在OpenSSL用户列表上打开:在运行时获取有效的OPENSSLDIR路径?

  • 我忽略了[版本文档](https://www.openssl.org/docs/manmaster/apps/version.html),我现在看到`opennsl version -d`的`OPENSSLDIR`标志.这对我有用,并且写得非常好,并且非常感谢.感谢您的时间! (4认同)

Nic*_*tte 6

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

openssl version -d
Run Code Online (Sandbox Code Playgroud)

如果这不起作用,则可以假定未正确配置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);
})();
Run Code Online (Sandbox Code Playgroud)