当前位置: 首页 > 知识库问答 >
问题:

使用openssl验证验证证书链

唐运诚
2023-03-14

我正在用以下组件构建自己的证书链:

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

什么是错的?

共有3个答案

鲁明知
2023-03-14

问题是,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设置,因为使用NginXhaproxy的人通常也能很好地阅读和理解这一设置;)

这是一个GitHub Gist,可能有一些更新

脚本的先决条件:

  • 你有可信的CA根数据在/etc/ssl/certs像往常一样,例如在Ubuntu
  • 创建一个目录DIR,其中存储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年里没有成为主流?这就是为什么。”努夫说。

锺伟志
2023-03-14

这是猫为数不多的合法工作之一:

openssl verify -verbose -CAfile <(cat Intermediate.pem RootCert.pem) UserCert.pem

更新:

正如格雷格·斯梅塞尔在评论中指出的,这个命令隐含地信任我ntermediate.pem.我建议阅读后格雷格引用的第一部分(第二部分是专门关于pyOpenSSL的,与这个问题无关)。

如果帖子消失了,我将引用以下重要段落:

不幸的是,当使用上面给出的推荐命令时,实际上是根/自签名的“中间”证书将被视为可信的证书:

验证文件

似乎一旦遇到根证书,openssl就会停止验证链,如果是自签名的,也可能是Intermediate.pem。在这种情况下,不考虑RootCert.pem。因此,在依赖上述命令之前,请确保Intermediate.pem来自受信任的源。

魏书
2023-03-14

验证文档:

如果发现一个证书是它自己的颁发者,则假定它是根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标题 得到了这个错误信息, 因此,我似乎输入了错误的函数格式,我仍然在谷歌上搜索,但欢迎任何帮助。 最后,我希望通过以下方式