使用openssl verify验证证书链


128

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

Root Certificate - Intermediate Certificate - User Certificate

根证书是自签名证书,中级证书由Root签名,用户由中级签名。

现在,我想通过根证书验证用户证书是否具有其锚点。

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

怎么了?

Answers:


164

verify文档:

如果找到的证书是其自己的颁发者,则将其视为根CA。

换句话说,根CA需要自签名才能验证工作。这就是为什么第二个命令不起作用的原因。尝试以下方法:

openssl verify -CAfile RootCert.pem -untrusted Intermediate.pem UserCert.pem

它将在一个命令中验证您的整个链。


2
我正在投票给这个答案,因为我最近不得不这样做,并且尝试了列出的其他选项后man verify,我发现该-untrusted参数是指定中间证书时使用的正确参数。
Anthony Geoghegan 2015年

我认为第二个答案:stackoverflow.com/a/31205833/173062更准确-将证书链传递给-CAfile参数。
Glenjamin

2
-untrusted不检查证书链是否完全有效。-CAfile正如其他问题所建议的那样,请考虑将中间级和根级传递给命令。
2016年

2
使用-untrusted为Intermediate.pem如果它有可能会发生以下情况:mail.python.org/pipermail/cryptography-dev/2016-August/...
格雷格Smethells

2
这不是OP要求的,但是如果您想验证不是自签名链,请使用系统/浏览器CA文件而不是您自己的文件。例如,在OS X上使用来自自制软件的openssl:openssl verify -CAfile /usr/local/etc/openssl/cert.pem -untrusted Intermediate.pem UserCert.pem
Greg Dubicki

50

那是为数不多的合法工作之一cat

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

更新:

正如Greg Smethells在评论中指出的那样, 此命令隐式信任Intermediate.pem。我建议阅读Greg帖子的第一部分(第二部分专门关于pyOpenSSL,与该问题无关)。

万一帖子消失了,我会引用重要的段落:

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

$ openssl verify -CAfile <(cat geotrust_global_ca.pem rogue_ca.pem)fake_sometechcompany_from_rogue_ca.com.pem fake_sometechcompany_from_rogue_ca.com.pem:OK

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


这是否会根据根证书实际验证中间证书?
2013年

是的 我只是使用一个我知道是正确的链(它为我的雇主提供生产流量)重新运行了这些命令,然后再次使用了另一个无关的根证书。见笔录要点
彼得

8
警告:如果根本信任Intermediate.pem,请不要使用此选项。欲了解更多信息在这里阅读:mail.python.org/pipermail/cryptography-dev/2016-August/...
格雷格Smethells

1
感谢您指出这一点,格雷格。当我给出答案时,我从发行人的主页下载了根目录和中间版本,因此我没有想到这一点。我已经更新了答案,以明确表明此命令暗中信任该中间体。
彼得

1
@somenickname,请参阅Tony的评论。无论如何,-untrusted选项是更可取的。我建议您问自己一个问题,是否需要进一步的帮助。注释不是调试问题的正确位置。
彼得

17

问题是,这openssl -verify不能完成任务。

正如Priyadi提到的那样,它会openssl -verify在第一个自签名证书处停止,因此您实际上并不会验证链,因为中间证书通常是自签名的。

我假设您想101%地确定证书文件是正确的,然后再尝试将其安装在生产性Web服务中。此处的配方完全执行了飞行前检查。

请注意,彼得的回答是正确的,但是输出的结果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捆绑包。有关如何准备捆绑包的信息,请参见下文。
  • 现在运行脚本: ./check DIR/certificate这假设脚本已命名check在当前目录中)
  • 脚本输出的可能性极小 CA-Bundle is not needed。这意味着您(阅读:/etc/ssl/certs/:)已经信任签名证书。但这在WWW中极不可能。
  • 对于此测试,必须在工作站上未使用端口4433。最好只在安全的环境中运行此程序,因为它会很快向公众开放端口4433,这可能会在恶意环境中看到外部连接。

如何创建certificate.bundle文件?

在WWW中,信任链通常如下所示:

  • 来自的受信任证书 /etc/ssl/certs
  • 未知的中间证书,可能由另一个CA交叉签名
  • 您的证书(certificate.crt

现在,评估从下到上进行,这意味着,首先,读取您的证书,然后需要未知的中间证书,然后可能是交叉签名证书,然后是 /etc/ssl/certs咨询以找到合适的受信任证书。

ca-bundle必须严格按照正确的处理顺序组成,这意味着,第一个需要的证书(签名您的证书的中间证书)在捆绑包中排在第一位。然后需要交叉签名证书。

通常,您的CA(签署证书的机构)已经提供了适当的ca-bundle文件。如果不是,则需要选择所有需要的中间证书,cat并将它们一起放入一个文件中(在Unix上)。在Windows上,您可以打开一个文本编辑器(例如notepad.exe),然后将证书粘贴到文件中,第一个需要放在顶部,其他要紧随其后。

还有另一件事。文件必须为PEM格式。某些CA发行DER(二进制)格式。PEM很容易发现:它是ASCII可读的。有关如何将某些内容转换为PEM的信息,请参阅如何将.crt转换为.pem并遵循黄砖路。

例:

你有:

  • intermediate2.crt 签署您的中间证书 certificate.crt
  • intermediate1.crt 另一个中级证书 intermediate2.crt
  • crossigned.crt 这是来自另一个CA的交叉签名证书 intermediate1.crt
  • crossintermediate.crt这是另一个已签名的CA的中间产品crossigned.crt(您可能永远不会看到这样的东西)

那么适当的cat将如下所示:

cat intermediate2.crt intermediate1.crt crossigned.crt crossintermediate.crt > certificate.bundle

以及如何找出需要哪些文件以及需要什么顺序?

好吧,进行实验,直到check告诉您一切都OK 为止。就像解决谜题的电脑益智游戏一样。每一个 单。时间。即使是专业人士。但是,每次需要这样做时,您都会变得更好。因此,您绝对不是唯一一个遭受如此痛苦的人。是SSL,您知道吗?SSL可能是30多年专业系统管理中最糟糕的设计之一。有没有想过为什么加密货币在过去30年没有成为主流?这就是为什么。纳夫说。


致下降投票者:请解释我的答案有什么问题。谢谢。
蒂诺

2
我是反对者之一。引发下降表决的原因是:“您如何才能找到需要或不需要哪些文件以及按什么顺序进行呢?好吧,尝试一下,直到检查告诉您一切正常为止”。我认为SSL不是特例。这样的问题应该有确定的解决方案。
ychaouche

2
@ychaouche谢谢!像你一样,我喜欢决定性的事情。问题是“什么地方错了”,以及如何使用“ openssl verify”来做到这一点。当我们讨论stackoverflow时,我解释了这一点,然后给出了程序性(因此确定性)的是/否答案。您甚至可以使用它来自动检查新的Bundle,然后再将其安装到生产环境中。这充分回答了这个问题。您不喜欢的是,我对“如何创建适当的捆绑包”感到沮丧。因为我认为不可能有一个确定性的简短答案,所以在这里上下文中回答这个问题将是不合时宜的。
蒂诺

6
“正如Priyadi所提到的,openssl -verify会在第一个自签名证书处停止,因此您不必真正验证链,因为中间证书通常是自签名的。” 显然,中间证书永远不会自签名(如果它们是根证书)。验证的全部重点是检查您是否已将链中的所有证书一直包含到受信任的根证书中。这正是openssl验证所做的。但是,openssl的信任政策往往较为保守……
Timo

4
“通常中间证书是自签名的”。这是错误的,并且这样的术语混淆使新手很难理解以正确的方式解释时实际上相当简单的主题。从RFC 5280开始:“ [...] CA证书可以进一步分为三类:交叉证书,自颁发证书和自签名证书。交叉证书是CA证书,其中颁发者和主题是不同的实体交叉证书描述了两个CA之间的信任关系。
Jan-Philip Gehrcke博士

8

我不得不对一个letencrypt证书进行验证,我这样做是这样的:

  1. letencrypt信任链中下载根证书和中间证书。
  2. 发出以下命令:

    $ openssl verify -CAfile letsencrypt-root-cert/isrgrootx1.pem.txt -untrusted letsencrypt-intermediate-cert/letsencryptauthorityx3.pem.txt /etc/letsencrypt/live/sitename.tld/cert.pem 
    /etc/letsencrypt/live/sitename.tld/cert.pem: OK
    

1
好吧,约翰似乎不喜欢我说的谢谢。我坚持要“谢谢”​​,所以这里是已删除​​的文本:希望它对您的letencrypt证书有所帮助。感谢Priyadi,您的解决方案帮助我找到了此命令。请确保支持他的解决方案。
迈克尔

5

在完全相同的问题上待了一整天之后,对SSL证书一无所知,我下载了CERTivity Keystores Manager并将我的密钥库导入其中,并获得了证书链的清晰可视化。

屏幕截图:

在此处输入图片说明


1
不要试图回答有关如何使用的问题openssl verify
binki'4

是的,但是如果您不了解openssl命令行工具的隐秘信息,则这种工具可以为您提供所需的可视化效果:)因此,我的观点是,可能还有一些在线工具也可以做到这一点。
David天宇Wong

2

如果你只是想验证发行人UserCert.pem 实际 Intermediate.pem执行下列操作(例如用途:OpenSSL 1.1.1):

openssl verify -no-CAfile -no-CApath -partial_chain -trusted Intermediate.pem UserCert.pem

您将获得:

UserCert.pem: OK

要么

UserCert.pem: verification failed

openssl verify -no-CAfile -no-CApath -partial_chain -trusted Intermediate.pem UserCert.pemPython 3.7中有任何等效命令吗?
波哥大

-5

您可以使用openssl轻松验证证书链。全链将包含CA证书,因此您应该查看有关CA和证书本身的详细信息。

openssl x509 -in fullchain.pem -text -noout


4
1)完全没有任何解释。2)这是对询问者未提出的问题的答案,没有任何上下文。
沙杜尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.