我正在编写一个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的条件:
$OPENSSL_CONF 变量已填充,文件存在/etc/ssl/openssl.cnf 存在如果这些都不是真的,那么它包括标准配置的副本.这是不合需要的,因为它实际上会覆盖客户端建立的自定义设置.我想完全使用环境条件,只需添加SAN部分作为附录.
我可以用通常的嫌疑人的路径甚至系统搜索进一步扩展这个链.但是如果存在多个,那么我无法保证openssl实际上将其用作默认值.
如何以编程方式确定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.cnf在OPENSSLDIR.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会发生什么时,cnf是NULL(即没有-config选项或OPENSSL_CONFENVAR).如果cnf是NULL没有覆盖,然后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路径?
如评论之一所述,简单的答案应该是使用以下命令查找路径:
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)