我正在用以下组件构建自己的证书链:
Root Certificate - Intermediate Certificate - User Certificate
根证书是自签名证书,中间证书由根证书和用户由中间证书签名。
现在我想验证一个用户证书是否有其根证书的锚。
具有
openssl verify -verbose -CAfile RootCert.pem Intermediate.pem
验证是可以的。在下一步中,我将使用
openssl verify -verbose -CAfile Intermediate.pem UserCert.pem
验证结果显示
error 20 at 0 depth lookup:unable to get local issuer certificate
什么是错的?
问题是,openssl-verify
不起作用。
正如Priyadi所提到的,openssl验证在第一个自签名证书处停止,因此您不会真正验证链,因为中间证书通常是自签名的。
我假设您希望在尝试将证书文件安装到生产性web服务中之前,有101%的把握证书文件是正确的。这里的配方正好执行飞行前检查。
请注意,Peter的回答是正确的,但是,openssl-verify
的输出并不能表明以后一切都正常工作。是的,它可能会发现一些问题,但不是全部。
下面是一个脚本,它在您将证书链安装到Apache之前验证证书链。也许这可以通过一些更神秘的OpenSSL魔法来增强,但我不是OpenSSL大师,我的工作如下:
#!/bin/bash
# This Works is placed under the terms of the Copyright Less License,
# see file COPYRIGHT.CLL. USE AT OWN RISK, ABSOLUTELY NO WARRANTY.
#
# COPYRIGHT.CLL can be found at http://permalink.de/tino/cll
# (CLL is CC0 as long as not covered by any Copyright)
OOPS() { echo "OOPS: $*" >&2; exit 23; }
PID=
kick() { [ -n "$PID" ] && kill "$PID" && sleep .2; PID=; }
trap 'kick' 0
serve()
{
kick
PID=
openssl s_server -key "$KEY" -cert "$CRT" "$@" -www &
PID=$!
sleep .5 # give it time to startup
}
check()
{
while read -r line
do
case "$line" in
'Verify return code: 0 (ok)') return 0;;
'Verify return code: '*) return 1;;
# *) echo "::: $line :::";;
esac
done < <(echo | openssl s_client -verify 8 -CApath /etc/ssl/certs/)
OOPS "Something failed, verification output not found!"
return 2
}
ARG="${1%.}"
KEY="$ARG.key"
CRT="$ARG.crt"
BND="$ARG.bundle"
for a in "$KEY" "$CRT" "$BND"
do
[ -s "$a" ] || OOPS "missing $a"
done
serve
check && echo "!!! =========> CA-Bundle is not needed! <========"
echo
serve -CAfile "$BND"
check
ret=$?
kick
echo
case $ret in
0) echo "EVERYTHING OK"
echo "SSLCertificateKeyFile $KEY"
echo "SSLCertificateFile $CRT"
echo "SSLCACertificateFile $BND"
;;
*) echo "!!! =========> something is wrong, verification failed! <======== ($ret)";;
esac
exit $ret
请注意,EVERYTHING OK
之后的输出是Apache设置,因为使用NginX
或haproxy
的人通常也能很好地阅读和理解这一设置;)
这是一个GitHub Gist,可能有一些更新
此脚本的先决条件:
/etc/ssl/certs
像往常一样,例如在UbuntuDIR
,其中存储3个文件:
DIR/certificate.crt
其中包含证书DIR/certificate.key
其中包含Web服务的密钥(没有密码)DIR/certificate.bundle
其中包含CA-Bundle。关于如何准备捆绑包,见下文。如何创建证书.bundle
文件?
在WWW中,信任链通常如下所示:
/etc/ssl/certs
现在,评估从下到上进行,这意味着,首先读取您的证书,然后需要未知的中间证书,然后可能需要交叉签名证书,然后查询/etc/ssl/certs
,以找到适当的受信任证书。
ca捆绑包必须严格按照正确的处理顺序组成,这意味着,第一个需要的证书(签署证书的中间证书)在捆绑包中首先出现。然后需要交叉签名证书。
通常您的CA(签署证书的机构)已经提供了这样一个适当的ca-bundle文件。如果没有,您需要选择所有需要的中间证书,并将它们合并到一个文件中(在Unix上)。在Windows上,您只需打开一个文本编辑器(如notepad.exe
)并将证书粘贴到文件中,第一个需要在上面,然后在其他后面。
还有一件事。这些文件需要采用PEM格式。一些CA发布DER(二进制)格式。PEM很容易识别:它是ASCII可读的。有关如何将某物转换为PEM的mor,请参阅如何将.crt转换为.PEM,然后沿着黄砖路走。
例子:
你有:
intermediate2.crt
签署您的证书的中间证书。crt
然后适当的cat
看起来像这样:
cat intermediate2.crt intermediate1.crt crossigned.crt crossintermediate.crt > certificate.bundle
你怎样才能知道哪些文件是需要的,哪些文件是不需要的,哪些文件的顺序是什么?
好吧,进行实验,直到检查告诉你一切正常。它就像一个电脑益智游戏来解开谜语。每一个仅有一个的时间即使是职业选手。但是每次你需要这样做的时候,你都会变得更好。因此,你肯定不是唯一一个承受所有痛苦的人。这是SSL,你知道吗?SSL可能是我在30多年的专业系统管理中见过的最糟糕的设计之一。有没有想过为什么加密技术在过去30年里没有成为主流?这就是为什么。”努夫说。
这是猫为数不多的合法工作之一:
openssl verify -verbose -CAfile <(cat Intermediate.pem RootCert.pem) UserCert.pem
更新:
正如格雷格·斯梅塞尔在评论中指出的,这个命令隐含地信任我ntermediate.pem.我建议阅读后格雷格引用的第一部分(第二部分是专门关于pyOpenSSL的,与这个问题无关)。
如果帖子消失了,我将引用以下重要段落:
不幸的是,当使用上面给出的推荐命令时,实际上是根/自签名的“中间”证书将被视为可信的证书:
验证文件
似乎一旦遇到根证书,openssl就会停止验证链,如果是自签名的,也可能是Intermediate.pem。在这种情况下,不考虑RootCert.pem。因此,在依赖上述命令之前,请确保Intermediate.pem来自受信任的源。
从验证
文档:
如果发现一个证书是它自己的颁发者,则假定它是根CA。
换句话说,根CA需要自我签名才能验证工作。这就是为什么你的第二个命令不起作用。试试这个吧:
openssl verify -CAfile RootCert.pem -untrusted Intermediate.pem UserCert.pem
它将在一个命令中验证您的整个链。
我试图使用Terraform创建一个自签名证书,以便在测试/开发环境中内部使用。 我首先创建一个CA私钥,自签名证书。 然后,为要启用HTTPS的内部域名创建证书签名请求和私钥。 然后我在证书上签字。以下是我使用的整个Terraform清单: 我查了Terraform舱单。然后我从状态文件中提取生成的证书并将它们保存到文件中。 我试图用openssl验证最终证书,但得到一个错误: 你知道问题出在哪
问题内容: 我将urllib3用于具有自签名证书的私有服务。有什么办法可以让urllib3忽略证书错误并仍然发出请求? 使用以下内容时: 引发以下错误: 使用我能够从服务中获得预期的响应 问题答案: 尝试以下代码: 请参阅将assert_hostname设置为False将禁用SSL主机名验证
问题内容: 我正在尝试通过调用HTTPS REST API 。在开发过程中,我偶然发现以下错误: 因此,我在Google上搜索了一下,并找到了很多可行的解决方案。 使用Jersey客户端的HTTPS https://gist.github.com/outbounder/1069465 如何解决“ java.security.cert.CertificateException:不存在使用者替代名称”
问题内容: 假设我编写了两个Java应用程序:并且它们被部署并在两个单独的服务器上运行(部署到和部署到),并且这两个应用程序需要通过SSL相互通信(双向)。我们还假设每个应用程序都有自己的SSL证书。 我(Java程序员)如何编码并验证彼此的SSL证书?每个CA是否都提供某种我可以使用的RESTful API ?Java是否有自己的证书验证API?我可以使用开放源代码的第三方JAR或服务吗? 当我
我正在尝试通过调用HTTPS REST API。在开发过程中,我偶然发现了以下错误: 所以我用谷歌搜索了一下,找到了大量的解决方案,实际上是有效的。 使用泽西客户端的HTTPS https://gist.github.com/outbounder/1069465 如何修复java.security.cert.证书异常:不存在主题替代名称错误? http://www.mkyong.com/webse
我正在尝试进行验证,我正在尝试使用PHP中的openssl库。但是我在将公钥传递到函数时遇到了问题。 这是一个基本代码,使用Net/DNS2库使用DNSSEC选项进行DNS查询。并获得DNSKEY和RRSIG。 我收到这个错误信息, 使用时: 所以我尝试添加BEGIN/END标题 得到了这个错误信息, 因此,我似乎输入了错误的函数格式,我仍然在谷歌上搜索,但欢迎任何帮助。 最后,我希望通过以下方式