确定私钥是否属于证书?

信息安全 密码学 openssl x.509
2021-08-22 16:07:35

给定证书¹和私钥文件²,我如何确定证书上的公钥是否与私钥匹配?

我最初的想法是简单地用证书上的公钥加密一些文本,并尝试用私钥解密它。如果它是往返的,我们就有了赢家。我只是不知道如何使用 OpenSSL 做到这一点。

或者,如果我可以从私钥生成公钥,我可以只比较他们的指纹。SSH 似乎对此有一个命令:

ssh-keygen -y -f my_key > my_key.pub

但是哈希值不匹配。(我几乎可以肯定我有与证书对应的密钥,因为网络服务器正在使用它,但我想要一种更简单的方法来启动服务器进行检查。)

¹ 一个.crt文件,x509 格式,我想。OpenSSL 可以通过以下方式读取它:

openssl x509 -text -in that_cert.crt

² 一个 RSA 私钥。

4个回答

我将假设您的当前目录中有 ssl.crt 和 ssl.key。

如果您想查看证书中的内容

# openssl x509 -in ssl.crt -text -noout

这里的两件事将是 RSA 公钥的模数和指数(以十六进制表示)。

如果您想查看私钥中的内容

# openssl rsa -in ssl.key -text -noout

请注意,公钥通常在那里(至少需要模数才能使私钥工作,并且公共指数通常是 65537 或 3)。因此,您可以简单地检查模数和公共指数是否匹配。当然,如果您想检查私钥是否确实有效(即 d 和 e 是模数 m 的有效 RSA 指数),您需要运行

# openssl rsa -check -in ssl.key -noout

编辑(2018 年): 请注意,如果您正在检查来自不受信任来源的私钥是否与证书对应,则必须检查私钥是否有效。有关不检查“泄露”私钥的有效性导致 CA 不正确地撤销证书的示例,请参见此处。如果您知道您有效地生成了密钥对,则可以跳过此步骤。

现在您可以简单地从证书和私钥生成公钥,然后diff用来检查它们是否不同:

# openssl x509 -in ssl.crt -pubkey -noout > from_crt.pub
# openssl rsa -in ssl.key -pubout > from_key.pub
# diff from_crt.pub from_key.pub

或者作为一个不创建文件的衬里(使用进程替换):

# diff  <(openssl x509 -in ssl.crt -pubkey -noout) <(openssl rsa -in ssl.key -pubout)

如果键匹配,则 diff 不应返回任何内容。(您可能会看到从第二个命令到 stderr 的“写入 RSA 密钥”输出)。

请注意,如果证书和私钥不匹配,您的网络服务器可能会大声抱怨。例如,对于 nginx 使用的证书,nginx 使用了错误的密钥(相同的大小,相同的公共指数,但去年的密钥):

# sudo /etc/init.d/nginx restart
* Restarting nginx nginx                                                                                         
nginx: [emerg] SSL_CTX_use_PrivateKey_file("/etc/nginx/ssl/private/wrong_key.key") failed 
(SSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch)
nginx: configuration file /etc/nginx/nginx.conf test failed

接受的答案是正确的,但它仅适用于 RSA 密钥。

至少从 openssl 1.1.1 开始,可以测试所有类型的私钥的有效性,这里有一个适用于 openssl 支持的各种密钥的单行器

 cmp <(openssl x509 -pubkey -in certificate.pem -noout) <(openssl pkey -check -pubout -in private-key.pem -outform PEM)

当且仅当私钥与证书中的公钥匹配时,它将返回“true”。

OpenSSL 可以创建一个测试 TLS 服务器,该服务器将在初始化时验证密钥和证书是否匹配:

openssl s_server -key key.pem -cert cert.pem

如果服务器启动,则密钥和证书匹配,否则服务器将无法启动并报错:

error setting private key
140606597580096:error:0B080074:x509 certificate routines:X509_check_private_key:\
key values mismatch:../crypto/x509/x509_cmp.c:297:

感谢 dave_thompson_085 在这个问题的评论中提出的建议。

使用可以使用的函数更新 Manish 的答案。用法:

ssl-cert-verify <key> <cert>

这是代码:

ssl-cert-verify() { local key="$1"; local cert="$2"; local opt="-check";
   cmp <(openssl x509 -pubkey -in "$cert" -noout) <(openssl pkey $opt -pubout -in "$key" -outform PEM)
}

使用旧版本的 SSL,我不得不将optvalue 留空。